review-council 4.1.8 → 4.1.9
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/README.md +10 -0
- package/dist/consensus/types.d.ts +2 -0
- package/dist/dispatch/adapter.d.ts +2 -0
- package/dist/dispatch/anthropic.js +125 -148
- package/dist/dispatch/anthropic.js.map +1 -1
- package/dist/dispatch/google.js +76 -108
- package/dist/dispatch/google.js.map +1 -1
- package/dist/dispatch/merge.js +4 -0
- package/dist/dispatch/merge.js.map +1 -1
- package/dist/dispatch/openai-compat.js +83 -106
- package/dist/dispatch/openai-compat.js.map +1 -1
- package/dist/dispatch/openai.js +73 -97
- package/dist/dispatch/openai.js.map +1 -1
- package/dist/dispatch/utils.d.ts +8 -1
- package/dist/dispatch/utils.js +63 -1
- package/dist/dispatch/utils.js.map +1 -1
- package/dist/models/stats-store.d.ts +13 -0
- package/dist/models/stats-store.js +440 -32
- package/dist/models/stats-store.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1091,6 +1091,16 @@ spec: SPEC.md
|
|
|
1091
1091
|
# githubToken: ghp_...
|
|
1092
1092
|
```
|
|
1093
1093
|
|
|
1094
|
+
`maxRetries` limits additional adapter SDK invocations after the first attempt;
|
|
1095
|
+
all attempts share the call's `timeout` and parent cancellation signal. Supported
|
|
1096
|
+
transient connection failures and HTTP status errors may retry; cancellation,
|
|
1097
|
+
expired deadlines, permanent TLS/configuration errors and unusable output do not.
|
|
1098
|
+
Report reviews and `ask` results expose `adapterAttempts` when observed. Chunk
|
|
1099
|
+
reports sum it only when every part has a known count. It is neither a wire-request
|
|
1100
|
+
count nor a billing total: lower-level activity and charges after ambiguous
|
|
1101
|
+
transport failures can be unknown. Token usage remains what the SDK response
|
|
1102
|
+
exposes, not proof of total charges across retries.
|
|
1103
|
+
|
|
1094
1104
|
Supported config file names: `.review-council.yml`, `.review-council.yaml`, `.review-council.json`. Executable JS config is never discovered: rcl often runs in untrusted checkouts with provider keys in the environment.
|
|
1095
1105
|
|
|
1096
1106
|
Verifier calls default to the remaining whole-pass budget. Set the optional
|
|
@@ -38,6 +38,8 @@ export interface TokenUsage {
|
|
|
38
38
|
reasoningTokens?: number;
|
|
39
39
|
}
|
|
40
40
|
export interface ModelReview {
|
|
41
|
+
/** Observed SDK invocations, including ambiguous failures; not wire requests or billing. */
|
|
42
|
+
adapterAttempts?: number;
|
|
41
43
|
model: string;
|
|
42
44
|
role: string;
|
|
43
45
|
provider: string;
|
|
@@ -11,6 +11,8 @@ export interface AdapterOptions {
|
|
|
11
11
|
}
|
|
12
12
|
/** A free-text answer from one model (discuss path — no findings schema). */
|
|
13
13
|
export interface ModelAnswer {
|
|
14
|
+
/** Observed SDK invocations, including ambiguous failures; not wire requests or billing. */
|
|
15
|
+
adapterAttempts?: number;
|
|
14
16
|
model: string;
|
|
15
17
|
provider: string;
|
|
16
18
|
text: string;
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
import Anthropic from '@anthropic-ai/sdk';
|
|
2
2
|
import { parseReviewOutput } from '../consensus/parser.js';
|
|
3
|
-
import { stripKnownProviderPrefix, isRetryableStatus,
|
|
3
|
+
import { stripKnownProviderPrefix, isRetryableStatus, attemptWithRetries, isRetryableConnectionError, failedReview, isBlankOutput, reviewFromParse, usageFromAnthropic, ASK_MAX_OUTPUT_TOKENS, TruncatedAnswerError, } from './utils.js';
|
|
4
4
|
function isRetryable(err) {
|
|
5
|
+
if (err instanceof Anthropic.APIConnectionError)
|
|
6
|
+
return isRetryableConnectionError(err, true);
|
|
5
7
|
return err instanceof Anthropic.APIError && isRetryableStatus(err.status);
|
|
6
8
|
}
|
|
7
9
|
function isRetryableReview(err, stream) {
|
|
10
|
+
if (err instanceof Anthropic.APIConnectionError || err instanceof Anthropic.APIUserAbortError)
|
|
11
|
+
return isRetryable(err);
|
|
8
12
|
if (isRetryable(err))
|
|
9
13
|
return true;
|
|
10
14
|
if (!stream)
|
|
@@ -16,10 +20,9 @@ function isRetryableReview(err, stream) {
|
|
|
16
20
|
(err.type === 'overloaded_error' || err.type === 'api_error' ||
|
|
17
21
|
err.type === 'rate_limit_error' || err.type === 'timeout_error'))
|
|
18
22
|
return true;
|
|
19
|
-
return err instanceof Anthropic.
|
|
20
|
-
(err
|
|
21
|
-
|
|
22
|
-
err.message === 'request ended without sending any chunks'));
|
|
23
|
+
return err instanceof Anthropic.AnthropicError &&
|
|
24
|
+
(err.message === 'stream ended without producing a Message with role=assistant' ||
|
|
25
|
+
err.message === 'request ended without sending any chunks');
|
|
23
26
|
}
|
|
24
27
|
const DEFAULT_PROFILE = { maxTokens: 16384, stream: false };
|
|
25
28
|
const FABLE_51_PROFILE = { maxTokens: 32768, effort: 'medium', stream: true };
|
|
@@ -43,178 +46,151 @@ export class AnthropicAdapter {
|
|
|
43
46
|
}
|
|
44
47
|
async review(model, role, systemPrompt, userPrompt, options) {
|
|
45
48
|
const start = Date.now();
|
|
46
|
-
|
|
47
|
-
const timeoutHandle = setTimeout(() => controller.abort(), options.timeoutMs);
|
|
48
|
-
const unlinkAbort = linkAbortSignal(controller, options.signal);
|
|
49
|
-
let lastErr = new Error('no attempts made');
|
|
49
|
+
let adapterAttempts = 0;
|
|
50
50
|
const modelId = stripKnownProviderPrefix(model);
|
|
51
51
|
// Fable 5.1 counts adaptive thinking against max_tokens. Large review
|
|
52
52
|
// chunks exhausted the old ceiling before any complete findings arrived.
|
|
53
53
|
const profile = profileFor(modelId);
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
enum: ['security', 'correctness', 'best-practices', 'tests', 'api-design'],
|
|
87
|
-
},
|
|
88
|
-
title: { type: 'string' },
|
|
89
|
-
description: { type: 'string' },
|
|
90
|
-
suggestedFix: { type: 'string' },
|
|
54
|
+
const outcome = await attemptWithRetries({
|
|
55
|
+
timeoutMs: options.timeoutMs,
|
|
56
|
+
maxRetries: options.maxRetries ?? 3,
|
|
57
|
+
signal: options.signal,
|
|
58
|
+
isRetryable: (err) => isRetryableReview(err, profile.stream),
|
|
59
|
+
attempt: async (signal) => {
|
|
60
|
+
// Use tool use for reliable JSON extraction
|
|
61
|
+
const request = {
|
|
62
|
+
model: modelId,
|
|
63
|
+
max_tokens: profile.maxTokens,
|
|
64
|
+
...(profile.effort ? { output_config: { effort: profile.effort } } : {}),
|
|
65
|
+
system: systemPrompt,
|
|
66
|
+
messages: [{ role: 'user', content: userPrompt }],
|
|
67
|
+
tools: [
|
|
68
|
+
{
|
|
69
|
+
name: 'report_findings',
|
|
70
|
+
description: 'Report code review findings as structured JSON',
|
|
71
|
+
input_schema: {
|
|
72
|
+
type: 'object',
|
|
73
|
+
properties: {
|
|
74
|
+
findings: {
|
|
75
|
+
type: 'array',
|
|
76
|
+
items: {
|
|
77
|
+
type: 'object',
|
|
78
|
+
properties: {
|
|
79
|
+
id: { type: 'string' },
|
|
80
|
+
file: { type: 'string' },
|
|
81
|
+
startLine: { type: 'number' },
|
|
82
|
+
endLine: { type: 'number' },
|
|
83
|
+
severity: {
|
|
84
|
+
type: 'string',
|
|
85
|
+
enum: ['critical', 'important', 'minor', 'nitpick'],
|
|
91
86
|
},
|
|
92
|
-
|
|
87
|
+
category: {
|
|
88
|
+
type: 'string',
|
|
89
|
+
enum: ['security', 'correctness', 'best-practices', 'tests', 'api-design'],
|
|
90
|
+
},
|
|
91
|
+
title: { type: 'string' },
|
|
92
|
+
description: { type: 'string' },
|
|
93
|
+
suggestedFix: { type: 'string' },
|
|
93
94
|
},
|
|
95
|
+
required: ['id', 'file', 'startLine', 'endLine', 'severity', 'category', 'title', 'description'],
|
|
94
96
|
},
|
|
95
97
|
},
|
|
96
|
-
required: ['findings'],
|
|
97
98
|
},
|
|
99
|
+
required: ['findings'],
|
|
98
100
|
},
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
provider: 'anthropic',
|
|
118
|
-
startedAt: start,
|
|
119
|
-
usage,
|
|
120
|
-
error: 'Response truncated at max_tokens; findings would be incomplete',
|
|
121
|
-
});
|
|
122
|
-
}
|
|
123
|
-
// Safety classifiers decline in-band: HTTP 200, no content. Left
|
|
124
|
-
// unhandled this reads as a clean review of code nobody looked at.
|
|
125
|
-
if (response.stop_reason === 'refusal') {
|
|
126
|
-
const details = response.stop_details;
|
|
127
|
-
const category = details !== null && details !== undefined && 'category' in details
|
|
128
|
-
? details.category
|
|
129
|
-
: null;
|
|
130
|
-
return failedReview({
|
|
131
|
-
model,
|
|
132
|
-
role,
|
|
133
|
-
provider: 'anthropic',
|
|
134
|
-
startedAt: start,
|
|
135
|
-
usage,
|
|
136
|
-
error: `Model refused this review${category ? ` (${category})` : ''} — the diff was not reviewed`,
|
|
137
|
-
});
|
|
138
|
-
}
|
|
139
|
-
// Extract from tool use
|
|
140
|
-
let rawOutput = '';
|
|
141
|
-
for (const block of response.content) {
|
|
142
|
-
if (block.type === 'tool_use' && block.name === 'report_findings') {
|
|
143
|
-
rawOutput = JSON.stringify(block.input);
|
|
144
|
-
break;
|
|
145
|
-
}
|
|
146
|
-
if (block.type === 'text') {
|
|
147
|
-
rawOutput += block.text;
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
if (isBlankOutput(rawOutput)) {
|
|
151
|
-
return failedReview({
|
|
152
|
-
model,
|
|
153
|
-
role,
|
|
154
|
-
provider: 'anthropic',
|
|
155
|
-
startedAt: start,
|
|
156
|
-
usage,
|
|
157
|
-
error: 'Model returned an empty response; the diff was not reviewed',
|
|
158
|
-
});
|
|
159
|
-
}
|
|
160
|
-
// If tool wasn't used, parse text output
|
|
161
|
-
const parsed = parseReviewOutput(rawOutput, model, role);
|
|
162
|
-
for (const w of parsed.warnings)
|
|
163
|
-
console.warn(w);
|
|
164
|
-
return reviewFromParse({
|
|
101
|
+
},
|
|
102
|
+
],
|
|
103
|
+
tool_choice: { type: 'auto' },
|
|
104
|
+
};
|
|
105
|
+
// Fable's larger output budget requires the SDK's streaming path.
|
|
106
|
+
// finalMessage() keeps the same complete-response parsing and
|
|
107
|
+
// truncation checks used by the nonstreaming path.
|
|
108
|
+
const requestOptions = {
|
|
109
|
+
signal: signal,
|
|
110
|
+
timeout: options.timeoutMs + 30_000,
|
|
111
|
+
};
|
|
112
|
+
adapterAttempts++;
|
|
113
|
+
const response = profile.stream
|
|
114
|
+
? await this.client.messages.stream(request, requestOptions).finalMessage()
|
|
115
|
+
: await this.client.messages.create(request, requestOptions);
|
|
116
|
+
const usage = usageFromAnthropic(response.usage);
|
|
117
|
+
if (response.stop_reason === 'max_tokens') {
|
|
118
|
+
return failedReview({
|
|
165
119
|
model,
|
|
166
120
|
role,
|
|
167
121
|
provider: 'anthropic',
|
|
168
122
|
startedAt: start,
|
|
169
|
-
parsed,
|
|
170
123
|
usage,
|
|
124
|
+
error: 'Response truncated at max_tokens; findings would be incomplete',
|
|
171
125
|
});
|
|
172
126
|
}
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
127
|
+
// Safety classifiers decline in-band: HTTP 200, no content. Left
|
|
128
|
+
// unhandled this reads as a clean review of code nobody looked at.
|
|
129
|
+
if (response.stop_reason === 'refusal') {
|
|
130
|
+
const details = response.stop_details;
|
|
131
|
+
const category = details !== null && details !== undefined && 'category' in details
|
|
132
|
+
? details.category
|
|
133
|
+
: null;
|
|
134
|
+
return failedReview({
|
|
135
|
+
model,
|
|
136
|
+
role,
|
|
137
|
+
provider: 'anthropic',
|
|
138
|
+
startedAt: start,
|
|
139
|
+
usage,
|
|
140
|
+
error: `Model refused this review${category ? ` (${category})` : ''} — the diff was not reviewed`,
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
// Extract from tool use
|
|
144
|
+
let rawOutput = '';
|
|
145
|
+
for (const block of response.content) {
|
|
146
|
+
if (block.type === 'tool_use' && block.name === 'report_findings') {
|
|
147
|
+
rawOutput = JSON.stringify(block.input);
|
|
148
|
+
break;
|
|
185
149
|
}
|
|
186
|
-
if (
|
|
187
|
-
|
|
188
|
-
continue;
|
|
150
|
+
if (block.type === 'text') {
|
|
151
|
+
rawOutput += block.text;
|
|
189
152
|
}
|
|
190
|
-
break;
|
|
191
153
|
}
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
154
|
+
if (isBlankOutput(rawOutput)) {
|
|
155
|
+
return failedReview({
|
|
156
|
+
model,
|
|
157
|
+
role,
|
|
158
|
+
provider: 'anthropic',
|
|
159
|
+
startedAt: start,
|
|
160
|
+
usage,
|
|
161
|
+
error: 'Model returned an empty response; the diff was not reviewed',
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
// If tool wasn't used, parse text output
|
|
165
|
+
const parsed = parseReviewOutput(rawOutput, model, role);
|
|
166
|
+
for (const w of parsed.warnings)
|
|
167
|
+
console.warn(w);
|
|
168
|
+
return reviewFromParse({
|
|
169
|
+
model,
|
|
170
|
+
role,
|
|
171
|
+
provider: 'anthropic',
|
|
172
|
+
startedAt: start,
|
|
173
|
+
parsed,
|
|
174
|
+
usage,
|
|
175
|
+
});
|
|
176
|
+
},
|
|
177
|
+
});
|
|
178
|
+
return outcome.ok
|
|
179
|
+
? { ...outcome.value, adapterAttempts }
|
|
180
|
+
: { ...failedReview({ model, role, provider: 'anthropic', startedAt: start,
|
|
181
|
+
status: outcome.timedOut ? 'timeout' : 'error', error: outcome.error }), adapterAttempts };
|
|
208
182
|
}
|
|
209
183
|
async ask(model, systemPrompt, userPrompt, options) {
|
|
210
184
|
const start = Date.now();
|
|
211
185
|
const modelId = stripKnownProviderPrefix(model);
|
|
186
|
+
let adapterAttempts = 0;
|
|
212
187
|
const outcome = await attemptWithRetries({
|
|
213
188
|
timeoutMs: options.timeoutMs,
|
|
214
189
|
maxRetries: options.maxRetries ?? 3,
|
|
215
190
|
signal: options.signal,
|
|
216
191
|
isRetryable,
|
|
217
192
|
attempt: async (signal) => {
|
|
193
|
+
adapterAttempts++;
|
|
218
194
|
const response = await this.client.messages.create({
|
|
219
195
|
model: modelId,
|
|
220
196
|
max_tokens: ASK_MAX_OUTPUT_TOKENS,
|
|
@@ -236,12 +212,13 @@ export class AnthropicAdapter {
|
|
|
236
212
|
});
|
|
237
213
|
const durationMs = Date.now() - start;
|
|
238
214
|
return outcome.ok
|
|
239
|
-
? { model, provider: 'anthropic', text: outcome.value, durationMs, status: 'success' }
|
|
215
|
+
? { model, provider: 'anthropic', text: outcome.value, durationMs, adapterAttempts, status: 'success' }
|
|
240
216
|
: {
|
|
241
217
|
model,
|
|
242
218
|
provider: 'anthropic',
|
|
243
219
|
text: '',
|
|
244
220
|
durationMs,
|
|
221
|
+
adapterAttempts,
|
|
245
222
|
status: outcome.timedOut ? 'timeout' : 'error',
|
|
246
223
|
error: outcome.error,
|
|
247
224
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"anthropic.js","sourceRoot":"","sources":["../../src/dispatch/anthropic.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,mBAAmB,CAAC;AAC1C,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAG3D,OAAO,EACL,wBAAwB,EACxB,iBAAiB,EACjB,
|
|
1
|
+
{"version":3,"file":"anthropic.js","sourceRoot":"","sources":["../../src/dispatch/anthropic.ts"],"names":[],"mappings":"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"}
|