@buoy-design/agents 0.1.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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Buoy
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,30 @@
1
+ import type { AcceptanceInput, AcceptanceResult, AgentResult } from './types.js';
2
+ export declare class AcceptanceAgent {
3
+ private client;
4
+ constructor(apiKey?: string);
5
+ /**
6
+ * Predict likelihood of PR acceptance for a repo
7
+ */
8
+ predict(input: AcceptanceInput): Promise<AgentResult<AcceptanceResult>>;
9
+ /**
10
+ * Build the prediction prompt
11
+ */
12
+ private buildPrompt;
13
+ /**
14
+ * Calculate PR statistics
15
+ */
16
+ private calculatePRStats;
17
+ /**
18
+ * Parse Claude's response
19
+ */
20
+ private parseResponse;
21
+ /**
22
+ * Parse and validate contribution process from response
23
+ */
24
+ private parseContributionProcess;
25
+ /**
26
+ * Validate likelihood value
27
+ */
28
+ private validateLikelihood;
29
+ }
30
+ //# sourceMappingURL=acceptance.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"acceptance.d.ts","sourceRoot":"","sources":["../src/acceptance.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,eAAe,EACf,gBAAgB,EAEhB,WAAW,EAEZ,MAAM,YAAY,CAAC;AAIpB,qBAAa,eAAe;IAC1B,OAAO,CAAC,MAAM,CAAY;gBAEd,MAAM,CAAC,EAAE,MAAM;IAM3B;;OAEG;IACG,OAAO,CAAC,KAAK,EAAE,eAAe,GAAG,OAAO,CAAC,WAAW,CAAC,gBAAgB,CAAC,CAAC;IA+B7E;;OAEG;IACH,OAAO,CAAC,WAAW;IA2DnB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IA2BxB;;OAEG;IACH,OAAO,CAAC,aAAa;IA0CrB;;OAEG;IACH,OAAO,CAAC,wBAAwB;IAuChC;;OAEG;IACH,OAAO,CAAC,kBAAkB;CAM3B"}
@@ -0,0 +1,205 @@
1
+ // packages/agents/src/acceptance.ts
2
+ // Predicts likelihood of PR acceptance
3
+ import Anthropic from '@anthropic-ai/sdk';
4
+ const MODEL = 'claude-sonnet-4-20250514';
5
+ export class AcceptanceAgent {
6
+ client;
7
+ constructor(apiKey) {
8
+ this.client = new Anthropic({
9
+ apiKey: apiKey ?? process.env.ANTHROPIC_API_KEY,
10
+ });
11
+ }
12
+ /**
13
+ * Predict likelihood of PR acceptance for a repo
14
+ */
15
+ async predict(input) {
16
+ try {
17
+ const prompt = this.buildPrompt(input);
18
+ const hasContributingMd = Boolean(input.contributingMd);
19
+ const response = await this.client.messages.create({
20
+ model: MODEL,
21
+ max_tokens: 2000,
22
+ messages: [{ role: 'user', content: prompt }],
23
+ });
24
+ const textContent = response.content.find((c) => c.type === 'text');
25
+ const responseText = textContent?.type === 'text' ? textContent.text : '';
26
+ const parsed = this.parseResponse(responseText, hasContributingMd);
27
+ return {
28
+ success: true,
29
+ data: parsed,
30
+ confidence: parsed.score / 100,
31
+ tokensUsed: response.usage.input_tokens + response.usage.output_tokens,
32
+ };
33
+ }
34
+ catch (error) {
35
+ return {
36
+ success: false,
37
+ error: error instanceof Error ? error.message : String(error),
38
+ confidence: 0,
39
+ };
40
+ }
41
+ }
42
+ /**
43
+ * Build the prediction prompt
44
+ */
45
+ buildPrompt(input) {
46
+ const prStats = this.calculatePRStats(input.recentPRs);
47
+ return `You are predicting whether a design system consistency PR will be accepted.
48
+
49
+ ## Repository
50
+ ${input.repo.owner}/${input.repo.name}
51
+ ${input.repo.description ? `Description: ${input.repo.description}` : ''}
52
+
53
+ ## Maintainer Activity
54
+ - Commits last month: ${input.maintainerActivity.commitsLastMonth}
55
+ - PRs reviewed last month: ${input.maintainerActivity.prsReviewedLastMonth}
56
+ - Avg review time: ${input.maintainerActivity.avgReviewTimeHours} hours
57
+
58
+ ## PR Statistics
59
+ - Total PRs analyzed: ${input.recentPRs.length}
60
+ - Merge rate: ${prStats.mergeRate}%
61
+ - Avg days open: ${prStats.avgDaysOpen}
62
+ - External contributor merge rate: ${prStats.externalMergeRate}%
63
+
64
+ ${input.contributingMd ? `## CONTRIBUTING.md\n${input.contributingMd.slice(0, 2000)}` : '## No CONTRIBUTING.md found'}
65
+
66
+ ${input.issueLabels?.length ? `## Issue Labels Used\n${input.issueLabels.join(', ')}` : ''}
67
+
68
+ ## Your Task
69
+
70
+ Predict likelihood of accepting a PR that:
71
+ - Fixes design system drift (hardcoded colors → tokens)
72
+ - Is a small, focused change (1-5 files)
73
+ - Has clear explanation of why the change matters
74
+ - Comes from an external contributor
75
+
76
+ **IMPORTANT**: Also extract the contribution process preference from CONTRIBUTING.md.
77
+ Look for phrases like:
78
+ - "open an issue first" / "please file an issue"
79
+ - "submit a PR directly" / "PRs welcome"
80
+ - "for small fixes, PRs are fine"
81
+ - "discuss in an issue before implementing"
82
+ - "RFC required for major changes"
83
+
84
+ Respond with JSON:
85
+ {
86
+ "likelihood": "high" | "medium" | "low",
87
+ "score": 0-100,
88
+ "reasoning": "2-3 sentences explaining your prediction",
89
+ "suggestedApproach": "How to frame the PR for best reception",
90
+ "redFlags": ["List of concerns"],
91
+ "greenFlags": ["List of positive signals"],
92
+ "contributionProcess": {
93
+ "issueRequired": true | false | "features-only" | "major-only",
94
+ "directPRsAllowed": "all" | "small-fixes" | "none",
95
+ "discussionFirst": true | false,
96
+ "preferredFlow": "issue-then-pr" | "pr-directly" | "discussion-first" | "depends-on-scope",
97
+ "evidence": "Direct quote from CONTRIBUTING.md (or 'No CONTRIBUTING.md found')",
98
+ "confidence": 0-100
99
+ }
100
+ }`;
101
+ }
102
+ /**
103
+ * Calculate PR statistics
104
+ */
105
+ calculatePRStats(prs) {
106
+ if (prs.length === 0) {
107
+ return { mergeRate: 0, avgDaysOpen: 0, externalMergeRate: 0 };
108
+ }
109
+ const merged = prs.filter((pr) => pr.merged);
110
+ const mergeRate = Math.round((merged.length / prs.length) * 100);
111
+ const avgDaysOpen = Math.round(prs.reduce((sum, pr) => sum + pr.daysOpen, 0) / prs.length);
112
+ // Assume external if author is not in first 3 commits (rough heuristic)
113
+ // In real implementation, you'd check against maintainer list
114
+ const externalPRs = prs.filter((pr) => pr.reviewComments > 0);
115
+ const externalMerged = externalPRs.filter((pr) => pr.merged);
116
+ const externalMergeRate = externalPRs.length > 0
117
+ ? Math.round((externalMerged.length / externalPRs.length) * 100)
118
+ : mergeRate;
119
+ return { mergeRate, avgDaysOpen, externalMergeRate };
120
+ }
121
+ /**
122
+ * Parse Claude's response
123
+ */
124
+ parseResponse(response, hasContributingMd) {
125
+ try {
126
+ const jsonMatch = response.match(/\{[\s\S]*\}/);
127
+ if (jsonMatch) {
128
+ const parsed = JSON.parse(jsonMatch[0]);
129
+ const result = {
130
+ likelihood: this.validateLikelihood(parsed.likelihood),
131
+ score: Math.min(100, Math.max(0, Number(parsed.score) || 50)),
132
+ reasoning: String(parsed.reasoning ?? ''),
133
+ suggestedApproach: String(parsed.suggestedApproach ?? ''),
134
+ redFlags: Array.isArray(parsed.redFlags)
135
+ ? parsed.redFlags.map(String)
136
+ : [],
137
+ greenFlags: Array.isArray(parsed.greenFlags)
138
+ ? parsed.greenFlags.map(String)
139
+ : [],
140
+ };
141
+ // Parse contribution process if present
142
+ if (parsed.contributionProcess) {
143
+ result.contributionProcess = this.parseContributionProcess(parsed.contributionProcess, hasContributingMd);
144
+ }
145
+ return result;
146
+ }
147
+ }
148
+ catch {
149
+ // Fall through
150
+ }
151
+ return {
152
+ likelihood: 'medium',
153
+ score: 50,
154
+ reasoning: 'Unable to analyze - defaulting to medium likelihood',
155
+ suggestedApproach: 'Follow standard contribution guidelines',
156
+ redFlags: [],
157
+ greenFlags: [],
158
+ };
159
+ }
160
+ /**
161
+ * Parse and validate contribution process from response
162
+ */
163
+ parseContributionProcess(raw, hasContributingMd) {
164
+ const obj = raw;
165
+ // Validate issueRequired
166
+ let issueRequired = false;
167
+ if (obj.issueRequired === true || obj.issueRequired === false) {
168
+ issueRequired = obj.issueRequired;
169
+ }
170
+ else if (obj.issueRequired === 'features-only' || obj.issueRequired === 'major-only') {
171
+ issueRequired = obj.issueRequired;
172
+ }
173
+ // Validate directPRsAllowed
174
+ let directPRsAllowed = 'all';
175
+ if (obj.directPRsAllowed === 'all' || obj.directPRsAllowed === 'small-fixes' || obj.directPRsAllowed === 'none') {
176
+ directPRsAllowed = obj.directPRsAllowed;
177
+ }
178
+ // Validate preferredFlow
179
+ let preferredFlow = 'depends-on-scope';
180
+ const validFlows = ['issue-then-pr', 'pr-directly', 'discussion-first', 'depends-on-scope'];
181
+ if (validFlows.includes(obj.preferredFlow)) {
182
+ preferredFlow = obj.preferredFlow;
183
+ }
184
+ return {
185
+ issueRequired,
186
+ directPRsAllowed,
187
+ discussionFirst: Boolean(obj.discussionFirst),
188
+ preferredFlow,
189
+ evidence: hasContributingMd
190
+ ? String(obj.evidence ?? 'Could not extract specific guidance')
191
+ : 'No CONTRIBUTING.md found',
192
+ confidence: Math.min(100, Math.max(0, Number(obj.confidence) || (hasContributingMd ? 70 : 30))),
193
+ };
194
+ }
195
+ /**
196
+ * Validate likelihood value
197
+ */
198
+ validateLikelihood(value) {
199
+ const valid = ['high', 'medium', 'low'];
200
+ return valid.includes(value)
201
+ ? value
202
+ : 'medium';
203
+ }
204
+ }
205
+ //# sourceMappingURL=acceptance.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"acceptance.js","sourceRoot":"","sources":["../src/acceptance.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ import type { FixabilityInput, FixabilityResult, AgentResult } from './types.js';
2
+ export declare class FixabilityAgent {
3
+ private client;
4
+ constructor(apiKey?: string);
5
+ /**
6
+ * Assess how fixable a drift signal is
7
+ */
8
+ assess(input: FixabilityInput): Promise<AgentResult<FixabilityResult>>;
9
+ /**
10
+ * Batch assess multiple signals (more efficient)
11
+ */
12
+ assessBatch(inputs: FixabilityInput[]): Promise<AgentResult<FixabilityResult>[]>;
13
+ /**
14
+ * Build the assessment prompt
15
+ */
16
+ private buildPrompt;
17
+ /**
18
+ * Parse Claude's response
19
+ */
20
+ private parseResponse;
21
+ /**
22
+ * Validate tier value
23
+ */
24
+ private validateTier;
25
+ /**
26
+ * Validate difficulty value
27
+ */
28
+ private validateDifficulty;
29
+ }
30
+ //# sourceMappingURL=fixability.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fixability.d.ts","sourceRoot":"","sources":["../src/fixability.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,eAAe,EACf,gBAAgB,EAGhB,WAAW,EACZ,MAAM,YAAY,CAAC;AAIpB,qBAAa,eAAe;IAC1B,OAAO,CAAC,MAAM,CAAY;gBAEd,MAAM,CAAC,EAAE,MAAM;IAM3B;;OAEG;IACG,MAAM,CAAC,KAAK,EAAE,eAAe,GAAG,OAAO,CAAC,WAAW,CAAC,gBAAgB,CAAC,CAAC;IA8B5E;;OAEG;IACG,WAAW,CACf,MAAM,EAAE,eAAe,EAAE,GACxB,OAAO,CAAC,WAAW,CAAC,gBAAgB,CAAC,EAAE,CAAC;IAgB3C;;OAEG;IACH,OAAO,CAAC,WAAW;IA2EnB;;OAEG;IACH,OAAO,CAAC,aAAa;IAiCrB;;OAEG;IACH,OAAO,CAAC,YAAY;IAKpB;;OAEG;IACH,OAAO,CAAC,kBAAkB;CAM3B"}
@@ -0,0 +1,182 @@
1
+ // packages/agents/src/fixability.ts
2
+ // Assesses how fixable a drift signal is
3
+ import Anthropic from '@anthropic-ai/sdk';
4
+ const MODEL = 'claude-haiku-4-20250514'; // Use Haiku for speed on many signals
5
+ export class FixabilityAgent {
6
+ client;
7
+ constructor(apiKey) {
8
+ this.client = new Anthropic({
9
+ apiKey: apiKey ?? process.env.ANTHROPIC_API_KEY,
10
+ });
11
+ }
12
+ /**
13
+ * Assess how fixable a drift signal is
14
+ */
15
+ async assess(input) {
16
+ try {
17
+ const prompt = this.buildPrompt(input);
18
+ const response = await this.client.messages.create({
19
+ model: MODEL,
20
+ max_tokens: 1000,
21
+ messages: [{ role: 'user', content: prompt }],
22
+ });
23
+ const textContent = response.content.find((c) => c.type === 'text');
24
+ const responseText = textContent?.type === 'text' ? textContent.text : '';
25
+ const parsed = this.parseResponse(responseText);
26
+ return {
27
+ success: true,
28
+ data: parsed,
29
+ confidence: parsed.tier === 'slam-dunk' ? 0.9 : 0.7,
30
+ tokensUsed: response.usage.input_tokens + response.usage.output_tokens,
31
+ };
32
+ }
33
+ catch (error) {
34
+ return {
35
+ success: false,
36
+ error: error instanceof Error ? error.message : String(error),
37
+ confidence: 0,
38
+ };
39
+ }
40
+ }
41
+ /**
42
+ * Batch assess multiple signals (more efficient)
43
+ */
44
+ async assessBatch(inputs) {
45
+ // Process in parallel with concurrency limit
46
+ const concurrency = 5;
47
+ const results = [];
48
+ for (let i = 0; i < inputs.length; i += concurrency) {
49
+ const batch = inputs.slice(i, i + concurrency);
50
+ const batchResults = await Promise.all(batch.map((input) => this.assess(input)));
51
+ results.push(...batchResults);
52
+ }
53
+ return results;
54
+ }
55
+ /**
56
+ * Build the assessment prompt
57
+ */
58
+ buildPrompt(input) {
59
+ const historyContext = input.historyContext
60
+ ? `
61
+ ## Git History Context
62
+ - Verdict: ${input.historyContext.verdict}
63
+ - Last modified: ${input.historyContext.lastModified}
64
+ - Authors: ${input.historyContext.authors.join(', ')}
65
+ - Context: ${input.historyContext.context}
66
+ `
67
+ : '';
68
+ const tokenContext = input.designTokens
69
+ ? `
70
+ ## Available Design Tokens
71
+ ${Object.entries(input.designTokens)
72
+ .slice(0, 20)
73
+ .map(([name, value]) => `- ${name}: ${value}`)
74
+ .join('\n')}
75
+ `
76
+ : '';
77
+ return `You are assessing whether a drift signal is worth fixing in an open source contribution.
78
+
79
+ ## Drift Signal
80
+ - Type: ${input.signal.type}
81
+ - File: ${input.signal.file}${input.signal.line ? `:${input.signal.line}` : ''}
82
+ - Severity: ${input.signal.severity}
83
+ - Message: ${input.signal.message}
84
+
85
+ ## File Content (around the issue)
86
+ \`\`\`
87
+ ${input.surroundingCode ?? input.fileContent.slice(0, 1000)}
88
+ \`\`\`
89
+
90
+ ${historyContext}
91
+ ${tokenContext}
92
+
93
+ ## Your Task
94
+
95
+ Assess this signal:
96
+
97
+ 1. **Tier**: Is this a slam-dunk fix, needs review, or should skip?
98
+ - slam-dunk: Clear mistake, safe to fix, token exists
99
+ - review: Probably fixable but needs human judgment
100
+ - skip: Intentional, risky, or too complex
101
+
102
+ 2. **Difficulty**: How hard is the fix?
103
+ - one-liner: Just replace one value
104
+ - moderate: Few lines, maybe a type change
105
+ - complex: Multiple files, logic changes
106
+
107
+ 3. **Intentional**: Is this drift intentional?
108
+ - Check for comments explaining the value
109
+ - Check if it's a special override
110
+ - Check git history context
111
+
112
+ 4. **Safe to Fix**: Could this break anything?
113
+
114
+ Respond with JSON:
115
+ {
116
+ "tier": "slam-dunk" | "review" | "skip",
117
+ "difficulty": "one-liner" | "moderate" | "complex",
118
+ "reasoning": "Brief explanation",
119
+ "intentional": true | false,
120
+ "safeToFix": true | false,
121
+ "suggestedFix": {
122
+ "before": "original code",
123
+ "after": "fixed code",
124
+ "explanation": "what changed"
125
+ }
126
+ }
127
+
128
+ The suggestedFix is optional - include only for slam-dunk tier.`;
129
+ }
130
+ /**
131
+ * Parse Claude's response
132
+ */
133
+ parseResponse(response) {
134
+ try {
135
+ const jsonMatch = response.match(/\{[\s\S]*\}/);
136
+ if (jsonMatch) {
137
+ const parsed = JSON.parse(jsonMatch[0]);
138
+ return {
139
+ tier: this.validateTier(parsed.tier),
140
+ difficulty: this.validateDifficulty(parsed.difficulty),
141
+ reasoning: String(parsed.reasoning ?? ''),
142
+ intentional: Boolean(parsed.intentional),
143
+ safeToFix: Boolean(parsed.safeToFix),
144
+ suggestedFix: parsed.suggestedFix
145
+ ? {
146
+ before: String(parsed.suggestedFix.before ?? ''),
147
+ after: String(parsed.suggestedFix.after ?? ''),
148
+ explanation: String(parsed.suggestedFix.explanation ?? ''),
149
+ }
150
+ : undefined,
151
+ };
152
+ }
153
+ }
154
+ catch {
155
+ // Fall through
156
+ }
157
+ return {
158
+ tier: 'skip',
159
+ difficulty: 'complex',
160
+ reasoning: 'Unable to analyze signal',
161
+ intentional: false,
162
+ safeToFix: false,
163
+ };
164
+ }
165
+ /**
166
+ * Validate tier value
167
+ */
168
+ validateTier(value) {
169
+ const valid = ['slam-dunk', 'review', 'skip'];
170
+ return valid.includes(value) ? value : 'skip';
171
+ }
172
+ /**
173
+ * Validate difficulty value
174
+ */
175
+ validateDifficulty(value) {
176
+ const valid = ['one-liner', 'moderate', 'complex'];
177
+ return valid.includes(value)
178
+ ? value
179
+ : 'complex';
180
+ }
181
+ }
182
+ //# sourceMappingURL=fixability.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fixability.js","sourceRoot":"","sources":["../src/fixability.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ import type { GeneratorInput, GeneratorResult, AgentResult } from './types.js';
2
+ export declare class GeneratorAgent {
3
+ private client;
4
+ constructor(apiKey?: string);
5
+ /**
6
+ * Generate fixes and PR description
7
+ */
8
+ generate(input: GeneratorInput): Promise<AgentResult<GeneratorResult>>;
9
+ /**
10
+ * Build the generation prompt
11
+ */
12
+ private buildPrompt;
13
+ /**
14
+ * Parse Claude's response
15
+ */
16
+ private parseResponse;
17
+ /**
18
+ * Validate fixes array
19
+ */
20
+ private validateFixes;
21
+ /**
22
+ * Build fallback PR body if parsing fails
23
+ */
24
+ private buildFallbackPRBody;
25
+ }
26
+ //# sourceMappingURL=generator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generator.d.ts","sourceRoot":"","sources":["../src/generator.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,cAAc,EACd,eAAe,EAEf,WAAW,EACZ,MAAM,YAAY,CAAC;AAIpB,qBAAa,cAAc;IACzB,OAAO,CAAC,MAAM,CAAY;gBAEd,MAAM,CAAC,EAAE,MAAM;IAM3B;;OAEG;IACG,QAAQ,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,CAAC,WAAW,CAAC,eAAe,CAAC,CAAC;IA8B5E;;OAEG;IACH,OAAO,CAAC,WAAW;IAsEnB;;OAEG;IACH,OAAO,CAAC,aAAa;IAkCrB;;OAEG;IACH,OAAO,CAAC,aAAa;IAqBrB;;OAEG;IACH,OAAO,CAAC,mBAAmB;CA8B5B"}