review-council 1.0.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/LICENSE +21 -0
- package/README.md +210 -0
- package/dist/config/defaults.d.ts +17 -0
- package/dist/config/defaults.js +27 -0
- package/dist/config/defaults.js.map +1 -0
- package/dist/config/loader.d.ts +2 -0
- package/dist/config/loader.js +66 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/config/schema.d.ts +79 -0
- package/dist/config/schema.js +49 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/consensus/deduper.d.ts +6 -0
- package/dist/consensus/deduper.js +127 -0
- package/dist/consensus/deduper.js.map +1 -0
- package/dist/consensus/parser.d.ts +6 -0
- package/dist/consensus/parser.js +90 -0
- package/dist/consensus/parser.js.map +1 -0
- package/dist/consensus/types.d.ts +57 -0
- package/dist/consensus/types.js +2 -0
- package/dist/consensus/types.js.map +1 -0
- package/dist/consensus/voter.d.ts +3 -0
- package/dist/consensus/voter.js +198 -0
- package/dist/consensus/voter.js.map +1 -0
- package/dist/dispatch/adapter.d.ts +15 -0
- package/dist/dispatch/adapter.js +24 -0
- package/dist/dispatch/adapter.js.map +1 -0
- package/dist/dispatch/anthropic.d.ts +9 -0
- package/dist/dispatch/anthropic.js +132 -0
- package/dist/dispatch/anthropic.js.map +1 -0
- package/dist/dispatch/google.d.ts +9 -0
- package/dist/dispatch/google.js +87 -0
- package/dist/dispatch/google.js.map +1 -0
- package/dist/dispatch/openai-compat.d.ts +18 -0
- package/dist/dispatch/openai-compat.js +90 -0
- package/dist/dispatch/openai-compat.js.map +1 -0
- package/dist/dispatch/openai.d.ts +9 -0
- package/dist/dispatch/openai.js +90 -0
- package/dist/dispatch/openai.js.map +1 -0
- package/dist/dispatch/runner.d.ts +11 -0
- package/dist/dispatch/runner.js +67 -0
- package/dist/dispatch/runner.js.map +1 -0
- package/dist/dispatch/utils.d.ts +6 -0
- package/dist/dispatch/utils.js +15 -0
- package/dist/dispatch/utils.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +262 -0
- package/dist/index.js.map +1 -0
- package/dist/output/github.d.ts +3 -0
- package/dist/output/github.js +95 -0
- package/dist/output/github.js.map +1 -0
- package/dist/output/json.d.ts +3 -0
- package/dist/output/json.js +8 -0
- package/dist/output/json.js.map +1 -0
- package/dist/output/markdown.d.ts +3 -0
- package/dist/output/markdown.js +81 -0
- package/dist/output/markdown.js.map +1 -0
- package/dist/output/terminal.d.ts +2 -0
- package/dist/output/terminal.js +141 -0
- package/dist/output/terminal.js.map +1 -0
- package/dist/prepare/chunker.d.ts +9 -0
- package/dist/prepare/chunker.js +62 -0
- package/dist/prepare/chunker.js.map +1 -0
- package/dist/prepare/language.d.ts +1 -0
- package/dist/prepare/language.js +99 -0
- package/dist/prepare/language.js.map +1 -0
- package/dist/prepare/prompt-builder.d.ts +11 -0
- package/dist/prepare/prompt-builder.js +65 -0
- package/dist/prepare/prompt-builder.js.map +1 -0
- package/dist/prompts/base.d.ts +3 -0
- package/dist/prompts/base.js +53 -0
- package/dist/prompts/base.js.map +1 -0
- package/dist/prompts/hardening.d.ts +7 -0
- package/dist/prompts/hardening.js +30 -0
- package/dist/prompts/hardening.js.map +1 -0
- package/dist/prompts/languages/elixir.d.ts +1 -0
- package/dist/prompts/languages/elixir.js +13 -0
- package/dist/prompts/languages/elixir.js.map +1 -0
- package/dist/prompts/languages/generic.d.ts +1 -0
- package/dist/prompts/languages/generic.js +11 -0
- package/dist/prompts/languages/generic.js.map +1 -0
- package/dist/prompts/languages/python.d.ts +1 -0
- package/dist/prompts/languages/python.js +14 -0
- package/dist/prompts/languages/python.js.map +1 -0
- package/dist/prompts/languages/typescript.d.ts +1 -0
- package/dist/prompts/languages/typescript.js +13 -0
- package/dist/prompts/languages/typescript.js.map +1 -0
- package/dist/resolver/github.d.ts +8 -0
- package/dist/resolver/github.js +70 -0
- package/dist/resolver/github.js.map +1 -0
- package/dist/resolver/local.d.ts +3 -0
- package/dist/resolver/local.js +75 -0
- package/dist/resolver/local.js.map +1 -0
- package/dist/resolver/types.d.ts +28 -0
- package/dist/resolver/types.js +2 -0
- package/dist/resolver/types.js.map +1 -0
- package/dist/roles/builtin.d.ts +4 -0
- package/dist/roles/builtin.js +234 -0
- package/dist/roles/builtin.js.map +1 -0
- package/dist/roles/dispatcher.d.ts +23 -0
- package/dist/roles/dispatcher.js +87 -0
- package/dist/roles/dispatcher.js.map +1 -0
- package/dist/roles/loader.d.ts +11 -0
- package/dist/roles/loader.js +107 -0
- package/dist/roles/loader.js.map +1 -0
- package/dist/roles/types.d.ts +13 -0
- package/dist/roles/types.js +2 -0
- package/dist/roles/types.js.map +1 -0
- package/package.json +67 -0
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
const FindingSchema = z.object({
|
|
3
|
+
id: z.string(),
|
|
4
|
+
file: z.string(),
|
|
5
|
+
startLine: z.number().int().nonnegative(),
|
|
6
|
+
endLine: z.number().int().nonnegative(),
|
|
7
|
+
severity: z.enum(['critical', 'important', 'minor', 'nitpick']),
|
|
8
|
+
category: z.enum(['security', 'correctness', 'best-practices', 'tests', 'api-design']),
|
|
9
|
+
title: z.string().max(200),
|
|
10
|
+
description: z.string(),
|
|
11
|
+
suggestedFix: z.string().optional(),
|
|
12
|
+
});
|
|
13
|
+
const ReviewOutputSchema = z.object({
|
|
14
|
+
findings: z.array(FindingSchema),
|
|
15
|
+
});
|
|
16
|
+
/**
|
|
17
|
+
* Extract JSON from a string that may have prose around it
|
|
18
|
+
*/
|
|
19
|
+
function extractJson(text) {
|
|
20
|
+
// Try direct parse first
|
|
21
|
+
const trimmed = text.trim();
|
|
22
|
+
if (trimmed.startsWith('{') || trimmed.startsWith('[')) {
|
|
23
|
+
return trimmed;
|
|
24
|
+
}
|
|
25
|
+
// Try to find JSON block in markdown code fences
|
|
26
|
+
const fenceMatch = text.match(/```(?:json)?\s*\n([\s\S]*?)\n```/);
|
|
27
|
+
if (fenceMatch) {
|
|
28
|
+
return fenceMatch[1].trim();
|
|
29
|
+
}
|
|
30
|
+
// Try to find the first { ... } block
|
|
31
|
+
const start = text.indexOf('{');
|
|
32
|
+
const end = text.lastIndexOf('}');
|
|
33
|
+
if (start >= 0 && end > start) {
|
|
34
|
+
return text.slice(start, end + 1);
|
|
35
|
+
}
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
export function parseReviewOutput(rawOutput, model, role) {
|
|
39
|
+
const warnings = [];
|
|
40
|
+
if (!rawOutput || rawOutput.trim().length === 0) {
|
|
41
|
+
warnings.push(`${model}/${role}: empty output`);
|
|
42
|
+
return { findings: [], warnings };
|
|
43
|
+
}
|
|
44
|
+
const jsonText = extractJson(rawOutput);
|
|
45
|
+
if (!jsonText) {
|
|
46
|
+
warnings.push(`${model}/${role}: could not extract JSON from output`);
|
|
47
|
+
return { findings: [], warnings };
|
|
48
|
+
}
|
|
49
|
+
let parsed;
|
|
50
|
+
try {
|
|
51
|
+
parsed = JSON.parse(jsonText);
|
|
52
|
+
}
|
|
53
|
+
catch (err) {
|
|
54
|
+
warnings.push(`${model}/${role}: JSON parse error: ${String(err)}`);
|
|
55
|
+
return { findings: [], warnings };
|
|
56
|
+
}
|
|
57
|
+
const result = ReviewOutputSchema.safeParse(parsed);
|
|
58
|
+
if (!result.success) {
|
|
59
|
+
// Try to salvage individual findings
|
|
60
|
+
if (typeof parsed === 'object' &&
|
|
61
|
+
parsed !== null &&
|
|
62
|
+
'findings' in parsed &&
|
|
63
|
+
Array.isArray(parsed.findings)) {
|
|
64
|
+
const rawFindings = parsed.findings;
|
|
65
|
+
const salvaged = [];
|
|
66
|
+
for (const item of rawFindings) {
|
|
67
|
+
const itemResult = FindingSchema.safeParse(item);
|
|
68
|
+
if (itemResult.success) {
|
|
69
|
+
salvaged.push(itemResult.data);
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
warnings.push(`${model}/${role}: dropped malformed finding: ${JSON.stringify(item).slice(0, 100)}`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
if (salvaged.length > 0) {
|
|
76
|
+
warnings.push(`${model}/${role}: schema validation errors (salvaged ${salvaged.length} findings)`);
|
|
77
|
+
return { findings: salvaged, warnings };
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
warnings.push(`${model}/${role}: schema validation failed: ${result.error.issues.map((e) => e.message).join(', ')}`);
|
|
81
|
+
return { findings: [], warnings };
|
|
82
|
+
}
|
|
83
|
+
// Assign stable IDs if missing or colliding
|
|
84
|
+
const findings = result.data.findings.map((f, i) => ({
|
|
85
|
+
...f,
|
|
86
|
+
id: f.id || `${model.replace(/[^a-z0-9]/gi, '')}_${role}_${i}`,
|
|
87
|
+
}));
|
|
88
|
+
return { findings, warnings };
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=parser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parser.js","sourceRoot":"","sources":["../../src/consensus/parser.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
export interface Finding {
|
|
2
|
+
id: string;
|
|
3
|
+
file: string;
|
|
4
|
+
startLine: number;
|
|
5
|
+
endLine: number;
|
|
6
|
+
severity: 'critical' | 'important' | 'minor' | 'nitpick';
|
|
7
|
+
category: 'security' | 'correctness' | 'best-practices' | 'tests' | 'api-design';
|
|
8
|
+
title: string;
|
|
9
|
+
description: string;
|
|
10
|
+
suggestedFix?: string;
|
|
11
|
+
}
|
|
12
|
+
export interface ModelReview {
|
|
13
|
+
model: string;
|
|
14
|
+
role: string;
|
|
15
|
+
provider: string;
|
|
16
|
+
findings: Finding[];
|
|
17
|
+
durationMs: number;
|
|
18
|
+
status: 'success' | 'timeout' | 'error';
|
|
19
|
+
error?: string;
|
|
20
|
+
}
|
|
21
|
+
export interface ConsensusInfo {
|
|
22
|
+
score: number;
|
|
23
|
+
total: number;
|
|
24
|
+
models: string[];
|
|
25
|
+
roles: string[];
|
|
26
|
+
crossRole: boolean;
|
|
27
|
+
crossModel: boolean;
|
|
28
|
+
elevated: boolean;
|
|
29
|
+
original_severity?: string;
|
|
30
|
+
elevation: 'none' | 'cross-role' | 'cross-model' | 'unanimous';
|
|
31
|
+
confidence: number;
|
|
32
|
+
confidenceLabel: 'Very High' | 'High' | 'Medium' | 'Low' | 'Minimal';
|
|
33
|
+
disputed?: boolean;
|
|
34
|
+
disputeDetails?: string;
|
|
35
|
+
}
|
|
36
|
+
export interface ConsensusFinding extends Finding {
|
|
37
|
+
consensus: ConsensusInfo;
|
|
38
|
+
}
|
|
39
|
+
export interface DeduplicatedGroup {
|
|
40
|
+
representative: Finding;
|
|
41
|
+
members: Array<{
|
|
42
|
+
finding: Finding;
|
|
43
|
+
model: string;
|
|
44
|
+
role: string;
|
|
45
|
+
}>;
|
|
46
|
+
}
|
|
47
|
+
export interface ReviewResult {
|
|
48
|
+
reviews: ModelReview[];
|
|
49
|
+
findings: ConsensusFinding[];
|
|
50
|
+
stats: {
|
|
51
|
+
totalReviews: number;
|
|
52
|
+
successfulReviews: number;
|
|
53
|
+
totalRawFindings: number;
|
|
54
|
+
totalDeduped: number;
|
|
55
|
+
durationMs: number;
|
|
56
|
+
};
|
|
57
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/consensus/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { ModelReview, ConsensusFinding, DeduplicatedGroup } from './types.js';
|
|
2
|
+
import type { Role } from '../roles/types.js';
|
|
3
|
+
export declare function computeConsensus(groups: DeduplicatedGroup[], reviews: ModelReview[], roleMap: Map<string, Role>): ConsensusFinding[];
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import { CONFIDENCE_THRESHOLDS } from '../config/defaults.js';
|
|
2
|
+
const SEVERITY_LEVELS = ['critical', 'important', 'minor', 'nitpick'];
|
|
3
|
+
function severityIndex(s) {
|
|
4
|
+
return SEVERITY_LEVELS.indexOf(s);
|
|
5
|
+
}
|
|
6
|
+
function indexToSeverity(i) {
|
|
7
|
+
const clamped = Math.max(0, Math.min(SEVERITY_LEVELS.length - 1, i));
|
|
8
|
+
return SEVERITY_LEVELS[clamped];
|
|
9
|
+
}
|
|
10
|
+
function bumpSeverity(severity, bumps) {
|
|
11
|
+
const idx = severityIndex(severity);
|
|
12
|
+
return indexToSeverity(idx - bumps); // lower index = higher severity
|
|
13
|
+
}
|
|
14
|
+
function confidenceLabel(score) {
|
|
15
|
+
if (score >= CONFIDENCE_THRESHOLDS.veryHigh)
|
|
16
|
+
return 'Very High';
|
|
17
|
+
if (score >= CONFIDENCE_THRESHOLDS.high)
|
|
18
|
+
return 'High';
|
|
19
|
+
if (score >= CONFIDENCE_THRESHOLDS.medium)
|
|
20
|
+
return 'Medium';
|
|
21
|
+
if (score >= CONFIDENCE_THRESHOLDS.low)
|
|
22
|
+
return 'Low';
|
|
23
|
+
return 'Minimal';
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Layer 2: Diversity score
|
|
27
|
+
* = (unique_models / total_models) * 0.5 + (unique_roles / total_roles) * 0.5
|
|
28
|
+
*/
|
|
29
|
+
function computeDiversity(group, allModels, allRoles) {
|
|
30
|
+
const uniqueModels = new Set(group.members.map((m) => m.model));
|
|
31
|
+
const uniqueRoles = new Set(group.members.map((m) => m.role));
|
|
32
|
+
const modelDiversity = allModels.length > 0 ? uniqueModels.size / allModels.length : 0;
|
|
33
|
+
const roleDiversity = allRoles.length > 0 ? uniqueRoles.size / allRoles.length : 0;
|
|
34
|
+
return modelDiversity * 0.5 + roleDiversity * 0.5;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Layer 2: Relevance score
|
|
38
|
+
* For each reporter's role, check if this category is in their focus area.
|
|
39
|
+
* Expected finding from focused role = 0.5, unexpected = 1.0; take mean.
|
|
40
|
+
*/
|
|
41
|
+
function computeRelevance(group, roleMap) {
|
|
42
|
+
if (group.members.length === 0)
|
|
43
|
+
return 0.5;
|
|
44
|
+
const scores = group.members.map(({ role: roleName }) => {
|
|
45
|
+
const role = roleMap.get(roleName);
|
|
46
|
+
if (!role)
|
|
47
|
+
return 1.0; // unknown role — treat as unexpected = high signal
|
|
48
|
+
const category = group.representative.category;
|
|
49
|
+
const isExpected = role.focus.includes(category) ||
|
|
50
|
+
role.focus.some((f) => f.includes(category) || category.includes(f));
|
|
51
|
+
return isExpected ? 0.5 : 1.0;
|
|
52
|
+
});
|
|
53
|
+
return scores.reduce((sum, s) => sum + s, 0) / scores.length;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Layer 2: Isolation score
|
|
57
|
+
* = flagged_relevant / (flagged_relevant + missed_relevant)
|
|
58
|
+
*
|
|
59
|
+
* "relevant" reviewers = those whose role.focus includes this category
|
|
60
|
+
* flagged_relevant = relevant reviewers who flagged this finding
|
|
61
|
+
* missed_relevant = relevant reviewers who did NOT flag this finding
|
|
62
|
+
*/
|
|
63
|
+
function computeIsolation(group, reviews, roleMap) {
|
|
64
|
+
const category = group.representative.category;
|
|
65
|
+
// Find all reviewers whose role is focused on this category
|
|
66
|
+
const relevantReviewers = reviews.filter((r) => {
|
|
67
|
+
if (r.status !== 'success')
|
|
68
|
+
return false;
|
|
69
|
+
const role = roleMap.get(r.role);
|
|
70
|
+
if (!role)
|
|
71
|
+
return false;
|
|
72
|
+
return (role.focus.includes(category) ||
|
|
73
|
+
role.focus.some((f) => f.includes(category) || category.includes(f)));
|
|
74
|
+
});
|
|
75
|
+
if (relevantReviewers.length === 0) {
|
|
76
|
+
// No focused reviewers — neutral score
|
|
77
|
+
return 0.5;
|
|
78
|
+
}
|
|
79
|
+
const flaggedModels = new Set(group.members.map((m) => `${m.model}::${m.role}`));
|
|
80
|
+
let flaggedRelevant = 0;
|
|
81
|
+
let missedRelevant = 0;
|
|
82
|
+
for (const reviewer of relevantReviewers) {
|
|
83
|
+
const key = `${reviewer.model}::${reviewer.role}`;
|
|
84
|
+
if (flaggedModels.has(key)) {
|
|
85
|
+
flaggedRelevant++;
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
missedRelevant++;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
const total = flaggedRelevant + missedRelevant;
|
|
92
|
+
return total > 0 ? flaggedRelevant / total : 0.5;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Layer 5: Detect opposing/disputed findings at the same location
|
|
96
|
+
*/
|
|
97
|
+
function detectDisputes(group, allGroups) {
|
|
98
|
+
const rep = group.representative;
|
|
99
|
+
// Look for another group at the same location with a contradicting title/description
|
|
100
|
+
for (const other of allGroups) {
|
|
101
|
+
if (other === group)
|
|
102
|
+
continue;
|
|
103
|
+
if (other.representative.file !== rep.file)
|
|
104
|
+
continue;
|
|
105
|
+
// Check if they're at the same location
|
|
106
|
+
const lineDiff = Math.abs(other.representative.startLine - rep.startLine);
|
|
107
|
+
if (lineDiff > 5)
|
|
108
|
+
continue;
|
|
109
|
+
// Check for opposing sentiment in titles
|
|
110
|
+
const aTitle = rep.title.toLowerCase();
|
|
111
|
+
const bTitle = other.representative.title.toLowerCase();
|
|
112
|
+
const opposingPairs = [
|
|
113
|
+
['missing', 'present'],
|
|
114
|
+
['no ', 'has '],
|
|
115
|
+
['lacks', 'has'],
|
|
116
|
+
['not ', 'is '],
|
|
117
|
+
['should add', 'should remove'],
|
|
118
|
+
];
|
|
119
|
+
for (const [posA, posB] of opposingPairs) {
|
|
120
|
+
if ((aTitle.includes(posA) && bTitle.includes(posB)) ||
|
|
121
|
+
(aTitle.includes(posB) && bTitle.includes(posA))) {
|
|
122
|
+
return {
|
|
123
|
+
disputed: true,
|
|
124
|
+
disputeDetails: `Conflicting finding at same location: "${rep.title}" vs "${other.representative.title}"`,
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return { disputed: false };
|
|
130
|
+
}
|
|
131
|
+
export function computeConsensus(groups, reviews, roleMap) {
|
|
132
|
+
const allModels = [...new Set(reviews.filter((r) => r.status === 'success').map((r) => r.model))];
|
|
133
|
+
const allRoles = [...new Set(reviews.filter((r) => r.status === 'success').map((r) => r.role))];
|
|
134
|
+
return groups.map((group) => {
|
|
135
|
+
const rep = group.representative;
|
|
136
|
+
// Layer 2: Signal scoring
|
|
137
|
+
const diversity = computeDiversity(group, allModels, allRoles);
|
|
138
|
+
const relevance = computeRelevance(group, roleMap);
|
|
139
|
+
const isolation = computeIsolation(group, reviews, roleMap);
|
|
140
|
+
// Layer 3: Raw confidence
|
|
141
|
+
const rawConfidence = diversity * 0.4 + relevance * 0.3 + isolation * 0.3;
|
|
142
|
+
const clampedConfidence = Math.min(1, Math.max(0, rawConfidence));
|
|
143
|
+
const label = confidenceLabel(clampedConfidence);
|
|
144
|
+
// Layer 4: Severity elevation
|
|
145
|
+
let elevatedSeverity = rep.severity;
|
|
146
|
+
let bumps = 0;
|
|
147
|
+
const elevation = (() => {
|
|
148
|
+
const uniqueModels = new Set(group.members.map((m) => m.model));
|
|
149
|
+
const uniqueRoles = new Set(group.members.map((m) => m.role));
|
|
150
|
+
if (label === 'Very High' &&
|
|
151
|
+
group.members.length >= 3) {
|
|
152
|
+
bumps = 2;
|
|
153
|
+
return 'unanimous';
|
|
154
|
+
}
|
|
155
|
+
if (label === 'High' || label === 'Very High') {
|
|
156
|
+
if (uniqueModels.size >= 2 && uniqueRoles.size >= 2) {
|
|
157
|
+
bumps = 1;
|
|
158
|
+
return 'cross-model';
|
|
159
|
+
}
|
|
160
|
+
if (uniqueRoles.size >= 2) {
|
|
161
|
+
bumps = 1;
|
|
162
|
+
return 'cross-role';
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
return 'none';
|
|
166
|
+
})();
|
|
167
|
+
if (bumps > 0) {
|
|
168
|
+
elevatedSeverity = bumpSeverity(rep.severity, bumps);
|
|
169
|
+
}
|
|
170
|
+
const elevated = elevatedSeverity !== rep.severity;
|
|
171
|
+
const original_severity = elevated ? rep.severity : undefined;
|
|
172
|
+
// Layer 5: Dispute detection
|
|
173
|
+
const { disputed, disputeDetails } = detectDisputes(group, groups);
|
|
174
|
+
const uniqueModels = [...new Set(group.members.map((m) => m.model))];
|
|
175
|
+
const uniqueRoles = [...new Set(group.members.map((m) => m.role))];
|
|
176
|
+
const consensus = {
|
|
177
|
+
score: group.members.length,
|
|
178
|
+
total: reviews.filter((r) => r.status === 'success').length,
|
|
179
|
+
models: uniqueModels,
|
|
180
|
+
roles: uniqueRoles,
|
|
181
|
+
crossRole: uniqueRoles.length >= 2,
|
|
182
|
+
crossModel: uniqueModels.length >= 2,
|
|
183
|
+
elevated,
|
|
184
|
+
original_severity,
|
|
185
|
+
elevation,
|
|
186
|
+
confidence: clampedConfidence,
|
|
187
|
+
confidenceLabel: label,
|
|
188
|
+
disputed: disputed || undefined,
|
|
189
|
+
disputeDetails,
|
|
190
|
+
};
|
|
191
|
+
return {
|
|
192
|
+
...rep,
|
|
193
|
+
severity: elevatedSeverity,
|
|
194
|
+
consensus,
|
|
195
|
+
};
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
//# sourceMappingURL=voter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"voter.js","sourceRoot":"","sources":["../../src/consensus/voter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ModelReview } from '../consensus/types.js';
|
|
2
|
+
export interface AdapterOptions {
|
|
3
|
+
timeoutMs: number;
|
|
4
|
+
maxRetries: number;
|
|
5
|
+
apiKey?: string;
|
|
6
|
+
baseUrl?: string;
|
|
7
|
+
}
|
|
8
|
+
export interface ReviewAdapter {
|
|
9
|
+
name: string;
|
|
10
|
+
provider: string;
|
|
11
|
+
review(model: string, role: string, systemPrompt: string, userPrompt: string, options: AdapterOptions): Promise<ModelReview>;
|
|
12
|
+
}
|
|
13
|
+
export declare function withTimeout<T>(promise: Promise<T>, ms: number): Promise<T>;
|
|
14
|
+
export declare function parseProviderFromModel(model: string): string;
|
|
15
|
+
export declare function stripProviderPrefix(model: string): string;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export function withTimeout(promise, ms) {
|
|
2
|
+
return new Promise((resolve, reject) => {
|
|
3
|
+
const timer = setTimeout(() => reject(new Error(`Timed out after ${ms}ms`)), ms);
|
|
4
|
+
promise.then((val) => { clearTimeout(timer); resolve(val); }, (err) => { clearTimeout(timer); reject(err); });
|
|
5
|
+
});
|
|
6
|
+
}
|
|
7
|
+
export function parseProviderFromModel(model) {
|
|
8
|
+
if (model.startsWith('claude'))
|
|
9
|
+
return 'anthropic';
|
|
10
|
+
if (model.startsWith('gpt') || model.startsWith('o1') || model.startsWith('o3') || model.startsWith('o4'))
|
|
11
|
+
return 'openai';
|
|
12
|
+
if (model.startsWith('gemini'))
|
|
13
|
+
return 'google';
|
|
14
|
+
// format: provider/model
|
|
15
|
+
if (model.includes('/'))
|
|
16
|
+
return model.split('/')[0];
|
|
17
|
+
return 'openai'; // default for unknown
|
|
18
|
+
}
|
|
19
|
+
export function stripProviderPrefix(model) {
|
|
20
|
+
if (model.includes('/'))
|
|
21
|
+
return model.split('/').slice(1).join('/');
|
|
22
|
+
return model;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter.js","sourceRoot":"","sources":["../../src/dispatch/adapter.ts"],"names":[],"mappings":"AAqBA,MAAM,UAAU,WAAW,CAAI,OAAmB,EAAE,EAAU;IAC5D,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,KAAK,GAAG,UAAU,CACtB,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,mBAAmB,EAAE,IAAI,CAAC,CAAC,EAClD,EAAE,CACH,CAAC;QACF,OAAO,CAAC,IAAI,CACV,CAAC,GAAG,EAAE,EAAE,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAC/C,CAAC,GAAG,EAAE,EAAE,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAC/C,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,KAAa;IAClD,IAAI,KAAK,CAAC,UAAU,CAAC,QAAQ,CAAC;QAAE,OAAO,WAAW,CAAC;IACnD,IAAI,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,QAAQ,CAAC;IAC3H,IAAI,KAAK,CAAC,UAAU,CAAC,QAAQ,CAAC;QAAE,OAAO,QAAQ,CAAC;IAChD,yBAAyB;IACzB,IAAI,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC;QAAE,OAAO,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAE,CAAC;IACrD,OAAO,QAAQ,CAAC,CAAC,sBAAsB;AACzC,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,KAAa;IAC/C,IAAI,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC;QAAE,OAAO,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACpE,OAAO,KAAK,CAAC;AACf,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ModelReview } from '../consensus/types.js';
|
|
2
|
+
import type { ReviewAdapter, AdapterOptions } from './adapter.js';
|
|
3
|
+
export declare class AnthropicAdapter implements ReviewAdapter {
|
|
4
|
+
name: string;
|
|
5
|
+
provider: string;
|
|
6
|
+
private client;
|
|
7
|
+
constructor(apiKey?: string);
|
|
8
|
+
review(model: string, role: string, systemPrompt: string, userPrompt: string, options: AdapterOptions): Promise<ModelReview>;
|
|
9
|
+
}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import Anthropic from '@anthropic-ai/sdk';
|
|
2
|
+
import { parseReviewOutput } from '../consensus/parser.js';
|
|
3
|
+
import { stripKnownProviderPrefix } from './utils.js';
|
|
4
|
+
const RETRY_DELAYS = [1000, 2000, 4000];
|
|
5
|
+
function isRetryable(err) {
|
|
6
|
+
if (err instanceof Anthropic.APIError) {
|
|
7
|
+
return err.status === 429 || err.status === 500 || err.status === 503;
|
|
8
|
+
}
|
|
9
|
+
return false;
|
|
10
|
+
}
|
|
11
|
+
export class AnthropicAdapter {
|
|
12
|
+
name = 'anthropic';
|
|
13
|
+
provider = 'anthropic';
|
|
14
|
+
client;
|
|
15
|
+
constructor(apiKey) {
|
|
16
|
+
this.client = new Anthropic({
|
|
17
|
+
apiKey: apiKey ?? process.env['ANTHROPIC_API_KEY'],
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
async review(model, role, systemPrompt, userPrompt, options) {
|
|
21
|
+
const start = Date.now();
|
|
22
|
+
const controller = new AbortController();
|
|
23
|
+
const timeoutHandle = setTimeout(() => controller.abort(), options.timeoutMs);
|
|
24
|
+
let lastErr = new Error('no attempts made');
|
|
25
|
+
const modelId = stripKnownProviderPrefix(model);
|
|
26
|
+
for (let attempt = 0; attempt <= (options.maxRetries ?? 3); attempt++) {
|
|
27
|
+
try {
|
|
28
|
+
// Use tool use for reliable JSON extraction
|
|
29
|
+
const response = await this.client.messages.create({
|
|
30
|
+
model: modelId,
|
|
31
|
+
max_tokens: 4096,
|
|
32
|
+
system: systemPrompt,
|
|
33
|
+
messages: [{ role: 'user', content: userPrompt }],
|
|
34
|
+
tools: [
|
|
35
|
+
{
|
|
36
|
+
name: 'report_findings',
|
|
37
|
+
description: 'Report code review findings as structured JSON',
|
|
38
|
+
input_schema: {
|
|
39
|
+
type: 'object',
|
|
40
|
+
properties: {
|
|
41
|
+
findings: {
|
|
42
|
+
type: 'array',
|
|
43
|
+
items: {
|
|
44
|
+
type: 'object',
|
|
45
|
+
properties: {
|
|
46
|
+
id: { type: 'string' },
|
|
47
|
+
file: { type: 'string' },
|
|
48
|
+
startLine: { type: 'number' },
|
|
49
|
+
endLine: { type: 'number' },
|
|
50
|
+
severity: {
|
|
51
|
+
type: 'string',
|
|
52
|
+
enum: ['critical', 'important', 'minor', 'nitpick'],
|
|
53
|
+
},
|
|
54
|
+
category: {
|
|
55
|
+
type: 'string',
|
|
56
|
+
enum: ['security', 'correctness', 'best-practices', 'tests', 'api-design'],
|
|
57
|
+
},
|
|
58
|
+
title: { type: 'string' },
|
|
59
|
+
description: { type: 'string' },
|
|
60
|
+
suggestedFix: { type: 'string' },
|
|
61
|
+
},
|
|
62
|
+
required: ['id', 'file', 'startLine', 'endLine', 'severity', 'category', 'title', 'description'],
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
required: ['findings'],
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
],
|
|
70
|
+
tool_choice: { type: 'any' },
|
|
71
|
+
}, { signal: controller.signal });
|
|
72
|
+
clearTimeout(timeoutHandle);
|
|
73
|
+
// Extract from tool use
|
|
74
|
+
let rawOutput = '';
|
|
75
|
+
for (const block of response.content) {
|
|
76
|
+
if (block.type === 'tool_use' && block.name === 'report_findings') {
|
|
77
|
+
rawOutput = JSON.stringify(block.input);
|
|
78
|
+
break;
|
|
79
|
+
}
|
|
80
|
+
if (block.type === 'text') {
|
|
81
|
+
rawOutput += block.text;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
// If tool wasn't used, parse text output
|
|
85
|
+
const { findings, warnings } = parseReviewOutput(rawOutput, model, role);
|
|
86
|
+
for (const w of warnings)
|
|
87
|
+
console.warn(w);
|
|
88
|
+
return {
|
|
89
|
+
model,
|
|
90
|
+
role,
|
|
91
|
+
provider: 'anthropic',
|
|
92
|
+
findings,
|
|
93
|
+
durationMs: Date.now() - start,
|
|
94
|
+
status: 'success',
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
catch (err) {
|
|
98
|
+
lastErr = err;
|
|
99
|
+
if (err instanceof Error && err.name === 'AbortError') {
|
|
100
|
+
clearTimeout(timeoutHandle);
|
|
101
|
+
return {
|
|
102
|
+
model,
|
|
103
|
+
role,
|
|
104
|
+
provider: 'anthropic',
|
|
105
|
+
findings: [],
|
|
106
|
+
durationMs: Date.now() - start,
|
|
107
|
+
status: 'timeout',
|
|
108
|
+
error: 'Request timed out',
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
if (isRetryable(err) && attempt < (options.maxRetries ?? 3)) {
|
|
112
|
+
const delay = RETRY_DELAYS[attempt] ?? 4000;
|
|
113
|
+
await new Promise((r) => setTimeout(r, delay));
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
break;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
clearTimeout(timeoutHandle);
|
|
120
|
+
const errMsg = lastErr instanceof Error ? `${lastErr.name}: ${lastErr.message}` : String(lastErr);
|
|
121
|
+
return {
|
|
122
|
+
model,
|
|
123
|
+
role,
|
|
124
|
+
provider: 'anthropic',
|
|
125
|
+
findings: [],
|
|
126
|
+
durationMs: Date.now() - start,
|
|
127
|
+
status: 'error',
|
|
128
|
+
error: errMsg,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
//# sourceMappingURL=anthropic.js.map
|
|
@@ -0,0 +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,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AAEtD,MAAM,YAAY,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;AAExC,SAAS,WAAW,CAAC,GAAY;IAC/B,IAAI,GAAG,YAAY,SAAS,CAAC,QAAQ,EAAE,CAAC;QACtC,OAAO,GAAG,CAAC,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,CAAC;IACxE,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,OAAO,gBAAgB;IAC3B,IAAI,GAAG,WAAW,CAAC;IACnB,QAAQ,GAAG,WAAW,CAAC;IAEf,MAAM,CAAY;IAE1B,YAAY,MAAe;QACzB,IAAI,CAAC,MAAM,GAAG,IAAI,SAAS,CAAC;YAC1B,MAAM,EAAE,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC;SACnD,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,MAAM,CACV,KAAa,EACb,IAAY,EACZ,YAAoB,EACpB,UAAkB,EAClB,OAAuB;QAEvB,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACzB,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;QACzC,MAAM,aAAa,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC;QAE9E,IAAI,OAAO,GAAY,IAAI,KAAK,CAAC,kBAAkB,CAAC,CAAC;QACrD,MAAM,OAAO,GAAG,wBAAwB,CAAC,KAAK,CAAC,CAAC;QAEhD,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,IAAI,CAAC,OAAO,CAAC,UAAU,IAAI,CAAC,CAAC,EAAE,OAAO,EAAE,EAAE,CAAC;YACtE,IAAI,CAAC;gBACH,4CAA4C;gBAC5C,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAChD;oBACE,KAAK,EAAE,OAAO;oBACd,UAAU,EAAE,IAAI;oBAChB,MAAM,EAAE,YAAY;oBACpB,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,CAAC;oBACjD,KAAK,EAAE;wBACL;4BACE,IAAI,EAAE,iBAAiB;4BACvB,WAAW,EAAE,gDAAgD;4BAC7D,YAAY,EAAE;gCACZ,IAAI,EAAE,QAAiB;gCACvB,UAAU,EAAE;oCACV,QAAQ,EAAE;wCACR,IAAI,EAAE,OAAO;wCACb,KAAK,EAAE;4CACL,IAAI,EAAE,QAAQ;4CACd,UAAU,EAAE;gDACV,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;gDACtB,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;gDACxB,SAAS,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;gDAC7B,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;gDAC3B,QAAQ,EAAE;oDACR,IAAI,EAAE,QAAQ;oDACd,IAAI,EAAE,CAAC,UAAU,EAAE,WAAW,EAAE,OAAO,EAAE,SAAS,CAAC;iDACpD;gDACD,QAAQ,EAAE;oDACR,IAAI,EAAE,QAAQ;oDACd,IAAI,EAAE,CAAC,UAAU,EAAE,aAAa,EAAE,gBAAgB,EAAE,OAAO,EAAE,YAAY,CAAC;iDAC3E;gDACD,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;gDACzB,WAAW,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;gDAC/B,YAAY,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;6CACjC;4CACD,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,SAAS,EAAE,UAAU,EAAE,UAAU,EAAE,OAAO,EAAE,aAAa,CAAC;yCACjG;qCACF;iCACF;gCACD,QAAQ,EAAE,CAAC,UAAU,CAAC;6BACvB;yBACF;qBACF;oBACD,WAAW,EAAE,EAAE,IAAI,EAAE,KAAc,EAAE;iBACtC,EACD,EAAE,MAAM,EAAE,UAAU,CAAC,MAAM,EAAE,CAC9B,CAAC;gBAEF,YAAY,CAAC,aAAa,CAAC,CAAC;gBAE5B,wBAAwB;gBACxB,IAAI,SAAS,GAAG,EAAE,CAAC;gBACnB,KAAK,MAAM,KAAK,IAAI,QAAQ,CAAC,OAAO,EAAE,CAAC;oBACrC,IAAI,KAAK,CAAC,IAAI,KAAK,UAAU,IAAI,KAAK,CAAC,IAAI,KAAK,iBAAiB,EAAE,CAAC;wBAClE,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;wBACxC,MAAM;oBACR,CAAC;oBACD,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;wBAC1B,SAAS,IAAI,KAAK,CAAC,IAAI,CAAC;oBAC1B,CAAC;gBACH,CAAC;gBAED,yCAAyC;gBACzC,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,iBAAiB,CAAC,SAAS,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;gBACzE,KAAK,MAAM,CAAC,IAAI,QAAQ;oBAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;gBAE1C,OAAO;oBACL,KAAK;oBACL,IAAI;oBACJ,QAAQ,EAAE,WAAW;oBACrB,QAAQ;oBACR,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK;oBAC9B,MAAM,EAAE,SAAS;iBAClB,CAAC;YACJ,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,OAAO,GAAG,GAAG,CAAC;gBACd,IAAI,GAAG,YAAY,KAAK,IAAI,GAAG,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;oBACtD,YAAY,CAAC,aAAa,CAAC,CAAC;oBAC5B,OAAO;wBACL,KAAK;wBACL,IAAI;wBACJ,QAAQ,EAAE,WAAW;wBACrB,QAAQ,EAAE,EAAE;wBACZ,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK;wBAC9B,MAAM,EAAE,SAAS;wBACjB,KAAK,EAAE,mBAAmB;qBAC3B,CAAC;gBACJ,CAAC;gBACD,IAAI,WAAW,CAAC,GAAG,CAAC,IAAI,OAAO,GAAG,CAAC,OAAO,CAAC,UAAU,IAAI,CAAC,CAAC,EAAE,CAAC;oBAC5D,MAAM,KAAK,GAAG,YAAY,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC;oBAC5C,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;oBAC/C,SAAS;gBACX,CAAC;gBACD,MAAM;YACR,CAAC;QACH,CAAC;QAED,YAAY,CAAC,aAAa,CAAC,CAAC;QAC5B,MAAM,MAAM,GAAG,OAAO,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,KAAK,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAClG,OAAO;YACL,KAAK;YACL,IAAI;YACJ,QAAQ,EAAE,WAAW;YACrB,QAAQ,EAAE,EAAE;YACZ,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK;YAC9B,MAAM,EAAE,OAAO;YACf,KAAK,EAAE,MAAM;SACd,CAAC;IACJ,CAAC;CACF"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ModelReview } from '../consensus/types.js';
|
|
2
|
+
import type { ReviewAdapter, AdapterOptions } from './adapter.js';
|
|
3
|
+
export declare class GoogleAdapter implements ReviewAdapter {
|
|
4
|
+
name: string;
|
|
5
|
+
provider: string;
|
|
6
|
+
private client;
|
|
7
|
+
constructor(apiKey?: string);
|
|
8
|
+
review(model: string, role: string, systemPrompt: string, userPrompt: string, options: AdapterOptions): Promise<ModelReview>;
|
|
9
|
+
}
|