@juspay/yama 2.0.0 → 2.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/CHANGELOG.md +12 -0
- package/dist/cli/v2.cli.js +69 -0
- package/dist/v2/config/DefaultConfig.js +13 -17
- package/dist/v2/core/LearningOrchestrator.d.ts +65 -0
- package/dist/v2/core/LearningOrchestrator.js +499 -0
- package/dist/v2/core/MCPServerManager.js +12 -4
- package/dist/v2/learning/FeedbackExtractor.d.ts +46 -0
- package/dist/v2/learning/FeedbackExtractor.js +237 -0
- package/dist/v2/learning/KnowledgeBaseManager.d.ts +91 -0
- package/dist/v2/learning/KnowledgeBaseManager.js +475 -0
- package/dist/v2/learning/types.d.ts +121 -0
- package/dist/v2/learning/types.js +15 -0
- package/dist/v2/prompts/LangfusePromptManager.d.ts +48 -0
- package/dist/v2/prompts/LangfusePromptManager.js +144 -0
- package/dist/v2/prompts/LearningSystemPrompt.d.ts +11 -0
- package/dist/v2/prompts/LearningSystemPrompt.js +180 -0
- package/dist/v2/prompts/PromptBuilder.d.ts +7 -0
- package/dist/v2/prompts/PromptBuilder.js +36 -7
- package/dist/v2/types/config.types.d.ts +22 -1
- package/package.json +7 -3
- package/yama.config.example.yaml +58 -13
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Langfuse Prompt Manager
|
|
3
|
+
* Fetches prompts from Langfuse Prompt Management with local fallbacks
|
|
4
|
+
*
|
|
5
|
+
* Prompt Names in Langfuse:
|
|
6
|
+
* - yama-review: Review system prompt
|
|
7
|
+
* - yama-enhancement: Enhancement system prompt
|
|
8
|
+
*/
|
|
9
|
+
import { Langfuse } from "langfuse";
|
|
10
|
+
import { REVIEW_SYSTEM_PROMPT } from "./ReviewSystemPrompt.js";
|
|
11
|
+
import { ENHANCEMENT_SYSTEM_PROMPT } from "./EnhancementSystemPrompt.js";
|
|
12
|
+
import { LEARNING_EXTRACTION_PROMPT, LEARNING_SUMMARIZATION_PROMPT, } from "./LearningSystemPrompt.js";
|
|
13
|
+
export class LangfusePromptManager {
|
|
14
|
+
client = null;
|
|
15
|
+
initialized = false;
|
|
16
|
+
constructor() {
|
|
17
|
+
this.initializeClient();
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Initialize Langfuse client if credentials are available
|
|
21
|
+
*/
|
|
22
|
+
initializeClient() {
|
|
23
|
+
const publicKey = process.env.LANGFUSE_PUBLIC_KEY;
|
|
24
|
+
const secretKey = process.env.LANGFUSE_SECRET_KEY;
|
|
25
|
+
const baseUrl = process.env.LANGFUSE_BASE_URL;
|
|
26
|
+
if (publicKey && secretKey) {
|
|
27
|
+
try {
|
|
28
|
+
this.client = new Langfuse({
|
|
29
|
+
publicKey,
|
|
30
|
+
secretKey,
|
|
31
|
+
baseUrl: baseUrl || "https://cloud.langfuse.com",
|
|
32
|
+
});
|
|
33
|
+
this.initialized = true;
|
|
34
|
+
console.log(" 📝 Langfuse prompt management enabled");
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
console.warn(" ⚠️ Failed to initialize Langfuse client:", error instanceof Error ? error.message : String(error));
|
|
38
|
+
this.client = null;
|
|
39
|
+
this.initialized = false;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Get the review system prompt
|
|
45
|
+
* Fetches from Langfuse if available, otherwise returns local fallback
|
|
46
|
+
*/
|
|
47
|
+
async getReviewPrompt() {
|
|
48
|
+
if (!this.client) {
|
|
49
|
+
return REVIEW_SYSTEM_PROMPT;
|
|
50
|
+
}
|
|
51
|
+
try {
|
|
52
|
+
const prompt = await this.client.getPrompt("yama-review", undefined, {
|
|
53
|
+
type: "text",
|
|
54
|
+
fallback: REVIEW_SYSTEM_PROMPT,
|
|
55
|
+
});
|
|
56
|
+
console.log(" ✅ Fetched review prompt from Langfuse");
|
|
57
|
+
return prompt.prompt;
|
|
58
|
+
}
|
|
59
|
+
catch (error) {
|
|
60
|
+
console.warn(" ⚠️ Failed to fetch review prompt from Langfuse, using fallback:", error instanceof Error ? error.message : String(error));
|
|
61
|
+
return REVIEW_SYSTEM_PROMPT;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Get the enhancement system prompt
|
|
66
|
+
* Fetches from Langfuse if available, otherwise returns local fallback
|
|
67
|
+
*/
|
|
68
|
+
async getEnhancementPrompt() {
|
|
69
|
+
if (!this.client) {
|
|
70
|
+
return ENHANCEMENT_SYSTEM_PROMPT;
|
|
71
|
+
}
|
|
72
|
+
try {
|
|
73
|
+
const prompt = await this.client.getPrompt("yama-enhancement", undefined, {
|
|
74
|
+
type: "text",
|
|
75
|
+
fallback: ENHANCEMENT_SYSTEM_PROMPT,
|
|
76
|
+
});
|
|
77
|
+
console.log(" ✅ Fetched enhancement prompt from Langfuse");
|
|
78
|
+
return prompt.prompt;
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
console.warn(" ⚠️ Failed to fetch enhancement prompt from Langfuse, using fallback:", error instanceof Error ? error.message : String(error));
|
|
82
|
+
return ENHANCEMENT_SYSTEM_PROMPT;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Get the learning extraction prompt
|
|
87
|
+
* Fetches from Langfuse if available, otherwise returns local fallback
|
|
88
|
+
* Langfuse prompt name: "yama-learning"
|
|
89
|
+
*/
|
|
90
|
+
async getLearningPrompt() {
|
|
91
|
+
if (!this.client) {
|
|
92
|
+
return LEARNING_EXTRACTION_PROMPT;
|
|
93
|
+
}
|
|
94
|
+
try {
|
|
95
|
+
const prompt = await this.client.getPrompt("yama-learning", undefined, {
|
|
96
|
+
type: "text",
|
|
97
|
+
fallback: LEARNING_EXTRACTION_PROMPT,
|
|
98
|
+
});
|
|
99
|
+
console.log(" ✅ Fetched learning prompt from Langfuse");
|
|
100
|
+
return prompt.prompt;
|
|
101
|
+
}
|
|
102
|
+
catch (error) {
|
|
103
|
+
console.warn(" ⚠️ Failed to fetch learning prompt from Langfuse, using fallback:", error instanceof Error ? error.message : String(error));
|
|
104
|
+
return LEARNING_EXTRACTION_PROMPT;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Get the summarization prompt
|
|
109
|
+
* Fetches from Langfuse if available, otherwise returns local fallback
|
|
110
|
+
* Langfuse prompt name: "yama-summarization"
|
|
111
|
+
*/
|
|
112
|
+
async getSummarizationPrompt() {
|
|
113
|
+
if (!this.client) {
|
|
114
|
+
return LEARNING_SUMMARIZATION_PROMPT;
|
|
115
|
+
}
|
|
116
|
+
try {
|
|
117
|
+
const prompt = await this.client.getPrompt("yama-summarization", undefined, {
|
|
118
|
+
type: "text",
|
|
119
|
+
fallback: LEARNING_SUMMARIZATION_PROMPT,
|
|
120
|
+
});
|
|
121
|
+
console.log(" ✅ Fetched summarization prompt from Langfuse");
|
|
122
|
+
return prompt.prompt;
|
|
123
|
+
}
|
|
124
|
+
catch (error) {
|
|
125
|
+
console.warn(" ⚠️ Failed to fetch summarization prompt from Langfuse, using fallback:", error instanceof Error ? error.message : String(error));
|
|
126
|
+
return LEARNING_SUMMARIZATION_PROMPT;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Check if Langfuse is enabled
|
|
131
|
+
*/
|
|
132
|
+
isEnabled() {
|
|
133
|
+
return this.initialized;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Shutdown Langfuse client gracefully
|
|
137
|
+
*/
|
|
138
|
+
async shutdown() {
|
|
139
|
+
if (this.client) {
|
|
140
|
+
await this.client.shutdownAsync();
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
//# sourceMappingURL=LangfusePromptManager.js.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Learning System Prompt
|
|
3
|
+
* Local fallback prompt for knowledge extraction from PR feedback
|
|
4
|
+
* Primary source: Langfuse (yama-learning)
|
|
5
|
+
*/
|
|
6
|
+
export declare const LEARNING_EXTRACTION_PROMPT = "\n<yama-learning-system>\n <role>Knowledge Extraction Analyst</role>\n <task>Extract project-level learnings from developer feedback on AI code reviews</task>\n\n <critical-principle>\n Your goal is to extract GENERIC, PROJECT-LEVEL knowledge.\n Remove PR-specific details. Create actionable guidelines.\n Ask: \"What should AI know for ALL future reviews of this project?\"\n </critical-principle>\n\n <instructions>\n For each AI comment + developer response pair provided:\n 1. Understand what the developer is teaching\n 2. Abstract into a project-level guideline\n 3. Categorize appropriately\n 4. Identify file patterns where this applies (if relevant)\n 5. Do NOT include PR-specific references (PR numbers, dates, developer names)\n </instructions>\n\n <categories>\n <category name=\"false_positive\">\n Things AI incorrectly flagged that should NOT be flagged.\n Use when developer says: \"this is intentional\", \"not an issue\", \"by design\", \"we prefer this\"\n Example: \"Promise.all() for parallel async is acceptable when awaited\"\n </category>\n\n <category name=\"missed_issue\">\n Things developer pointed out that AI should have caught.\n Use when developer says: \"you missed\", \"also check\", \"what about\"\n Example: \"Always validate JWT audience in multi-tenant endpoints\"\n </category>\n\n <category name=\"style_preference\">\n Team conventions that differ from general best practices.\n Use when developer says: \"we prefer\", \"our convention\", \"team decision\"\n Example: \"Use type over interface for all type definitions\"\n </category>\n\n <category name=\"domain_context\">\n Project-specific architecture or context AI needs.\n Use when developer explains project structure, dependencies, or patterns.\n Example: \"src/services/ contains business logic, handlers are thin wrappers\"\n </category>\n\n <category name=\"enhancement_guideline\">\n How AI should approach suggestions for this project.\n Use when developer guides on comment style, severity, or scope.\n Example: \"Don't suggest JSDoc for internal functions\"\n </category>\n </categories>\n\n <output-format>\n Return a JSON array of learnings. Each learning should be:\n - Actionable and specific\n - Generic (applicable to future reviews)\n - Free of PR-specific details\n\n Format:\n [\n {\n \"category\": \"false_positive\",\n \"subcategory\": \"Async Patterns\",\n \"learning\": \"Clear, actionable guideline for future reviews...\",\n \"filePatterns\": [\"**/services/**/*.ts\"],\n \"reasoning\": \"Brief explanation of why this matters\"\n }\n ]\n\n Return an EMPTY array [] if no actionable learnings can be extracted.\n </output-format>\n\n <examples>\n <example>\n <ai-comment>\n \uD83D\uDD12 SECURITY: This Promise.all() could cause memory issues if the array is large.\n Consider using batching.\n </ai-comment>\n <developer-reply>\n This is intentional - we want parallel execution here for performance.\n The array is always small (< 10 items) from our API pagination.\n </developer-reply>\n <extracted-learning>\n {\n \"category\": \"false_positive\",\n \"subcategory\": \"Async Patterns\",\n \"learning\": \"Promise.all() for parallel async operations is acceptable when the collection size is bounded and known to be small\",\n \"filePatterns\": null,\n \"reasoning\": \"Team uses Promise.all() intentionally for performance with small, bounded collections\"\n }\n </extracted-learning>\n </example>\n\n <example>\n <ai-comment>\n \u26A0\uFE0F MAJOR: Consider adding input validation for this API endpoint.\n </ai-comment>\n <developer-reply>\n Good point, but you missed that we also need to sanitize the input\n before logging - we had a PII exposure issue before.\n </developer-reply>\n <extracted-learning>\n {\n \"category\": \"missed_issue\",\n \"subcategory\": \"Security\",\n \"learning\": \"Sanitize user input before logging to prevent PII exposure\",\n \"filePatterns\": [\"**/api/**\", \"**/handlers/**\"],\n \"reasoning\": \"Historical PII exposure issue - logging must use sanitized values\"\n }\n </extracted-learning>\n </example>\n\n <example>\n <ai-comment>\n \uD83D\uDCA1 MINOR: Consider using 'interface' instead of 'type' for object shapes.\n </ai-comment>\n <developer-reply>\n We prefer 'type' for everything in this project - team decision.\n </developer-reply>\n <extracted-learning>\n {\n \"category\": \"style_preference\",\n \"subcategory\": \"TypeScript\",\n \"learning\": \"Use 'type' over 'interface' for all type definitions\",\n \"filePatterns\": [\"**/*.ts\", \"**/*.tsx\"],\n \"reasoning\": \"Team convention to use type aliases consistently\"\n }\n </extracted-learning>\n </example>\n </examples>\n</yama-learning-system>\n";
|
|
7
|
+
/**
|
|
8
|
+
* Summarization prompt for consolidating knowledge base entries
|
|
9
|
+
*/
|
|
10
|
+
export declare const LEARNING_SUMMARIZATION_PROMPT = "\n<yama-summarization-task>\n <goal>Consolidate knowledge base learnings into concise, actionable guidelines</goal>\n\n <instructions>\n You will receive the current knowledge base content.\n For each category section:\n 1. Identify duplicate or highly similar learnings\n 2. Merge related learnings into single statements\n 3. Keep the most general, actionable form\n 4. Preserve file patterns where applicable\n 5. Ensure no information is lost, just condensed\n </instructions>\n\n <rules>\n - Combine learnings that say the same thing differently\n - Keep specific technical details (don't over-generalize)\n - Preserve all unique learnings\n - Maintain subcategory organization\n - Update the total count accurately\n </rules>\n\n <example>\n Before:\n - Don't flag Promise.all() in services\n - Promise.all() is acceptable in async handlers\n - Parallel Promise execution is intentional\n\n After:\n - Promise.all() for parallel async operations is acceptable across the codebase\n </example>\n\n <output-format>\n Return the complete, updated knowledge base in markdown format.\n Preserve the exact structure (headers, sections, metadata).\n Update the metadata with new total count and summarization timestamp.\n </output-format>\n</yama-summarization-task>\n";
|
|
11
|
+
//# sourceMappingURL=LearningSystemPrompt.d.ts.map
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Learning System Prompt
|
|
3
|
+
* Local fallback prompt for knowledge extraction from PR feedback
|
|
4
|
+
* Primary source: Langfuse (yama-learning)
|
|
5
|
+
*/
|
|
6
|
+
export const LEARNING_EXTRACTION_PROMPT = `
|
|
7
|
+
<yama-learning-system>
|
|
8
|
+
<role>Knowledge Extraction Analyst</role>
|
|
9
|
+
<task>Extract project-level learnings from developer feedback on AI code reviews</task>
|
|
10
|
+
|
|
11
|
+
<critical-principle>
|
|
12
|
+
Your goal is to extract GENERIC, PROJECT-LEVEL knowledge.
|
|
13
|
+
Remove PR-specific details. Create actionable guidelines.
|
|
14
|
+
Ask: "What should AI know for ALL future reviews of this project?"
|
|
15
|
+
</critical-principle>
|
|
16
|
+
|
|
17
|
+
<instructions>
|
|
18
|
+
For each AI comment + developer response pair provided:
|
|
19
|
+
1. Understand what the developer is teaching
|
|
20
|
+
2. Abstract into a project-level guideline
|
|
21
|
+
3. Categorize appropriately
|
|
22
|
+
4. Identify file patterns where this applies (if relevant)
|
|
23
|
+
5. Do NOT include PR-specific references (PR numbers, dates, developer names)
|
|
24
|
+
</instructions>
|
|
25
|
+
|
|
26
|
+
<categories>
|
|
27
|
+
<category name="false_positive">
|
|
28
|
+
Things AI incorrectly flagged that should NOT be flagged.
|
|
29
|
+
Use when developer says: "this is intentional", "not an issue", "by design", "we prefer this"
|
|
30
|
+
Example: "Promise.all() for parallel async is acceptable when awaited"
|
|
31
|
+
</category>
|
|
32
|
+
|
|
33
|
+
<category name="missed_issue">
|
|
34
|
+
Things developer pointed out that AI should have caught.
|
|
35
|
+
Use when developer says: "you missed", "also check", "what about"
|
|
36
|
+
Example: "Always validate JWT audience in multi-tenant endpoints"
|
|
37
|
+
</category>
|
|
38
|
+
|
|
39
|
+
<category name="style_preference">
|
|
40
|
+
Team conventions that differ from general best practices.
|
|
41
|
+
Use when developer says: "we prefer", "our convention", "team decision"
|
|
42
|
+
Example: "Use type over interface for all type definitions"
|
|
43
|
+
</category>
|
|
44
|
+
|
|
45
|
+
<category name="domain_context">
|
|
46
|
+
Project-specific architecture or context AI needs.
|
|
47
|
+
Use when developer explains project structure, dependencies, or patterns.
|
|
48
|
+
Example: "src/services/ contains business logic, handlers are thin wrappers"
|
|
49
|
+
</category>
|
|
50
|
+
|
|
51
|
+
<category name="enhancement_guideline">
|
|
52
|
+
How AI should approach suggestions for this project.
|
|
53
|
+
Use when developer guides on comment style, severity, or scope.
|
|
54
|
+
Example: "Don't suggest JSDoc for internal functions"
|
|
55
|
+
</category>
|
|
56
|
+
</categories>
|
|
57
|
+
|
|
58
|
+
<output-format>
|
|
59
|
+
Return a JSON array of learnings. Each learning should be:
|
|
60
|
+
- Actionable and specific
|
|
61
|
+
- Generic (applicable to future reviews)
|
|
62
|
+
- Free of PR-specific details
|
|
63
|
+
|
|
64
|
+
Format:
|
|
65
|
+
[
|
|
66
|
+
{
|
|
67
|
+
"category": "false_positive",
|
|
68
|
+
"subcategory": "Async Patterns",
|
|
69
|
+
"learning": "Clear, actionable guideline for future reviews...",
|
|
70
|
+
"filePatterns": ["**/services/**/*.ts"],
|
|
71
|
+
"reasoning": "Brief explanation of why this matters"
|
|
72
|
+
}
|
|
73
|
+
]
|
|
74
|
+
|
|
75
|
+
Return an EMPTY array [] if no actionable learnings can be extracted.
|
|
76
|
+
</output-format>
|
|
77
|
+
|
|
78
|
+
<examples>
|
|
79
|
+
<example>
|
|
80
|
+
<ai-comment>
|
|
81
|
+
🔒 SECURITY: This Promise.all() could cause memory issues if the array is large.
|
|
82
|
+
Consider using batching.
|
|
83
|
+
</ai-comment>
|
|
84
|
+
<developer-reply>
|
|
85
|
+
This is intentional - we want parallel execution here for performance.
|
|
86
|
+
The array is always small (< 10 items) from our API pagination.
|
|
87
|
+
</developer-reply>
|
|
88
|
+
<extracted-learning>
|
|
89
|
+
{
|
|
90
|
+
"category": "false_positive",
|
|
91
|
+
"subcategory": "Async Patterns",
|
|
92
|
+
"learning": "Promise.all() for parallel async operations is acceptable when the collection size is bounded and known to be small",
|
|
93
|
+
"filePatterns": null,
|
|
94
|
+
"reasoning": "Team uses Promise.all() intentionally for performance with small, bounded collections"
|
|
95
|
+
}
|
|
96
|
+
</extracted-learning>
|
|
97
|
+
</example>
|
|
98
|
+
|
|
99
|
+
<example>
|
|
100
|
+
<ai-comment>
|
|
101
|
+
⚠️ MAJOR: Consider adding input validation for this API endpoint.
|
|
102
|
+
</ai-comment>
|
|
103
|
+
<developer-reply>
|
|
104
|
+
Good point, but you missed that we also need to sanitize the input
|
|
105
|
+
before logging - we had a PII exposure issue before.
|
|
106
|
+
</developer-reply>
|
|
107
|
+
<extracted-learning>
|
|
108
|
+
{
|
|
109
|
+
"category": "missed_issue",
|
|
110
|
+
"subcategory": "Security",
|
|
111
|
+
"learning": "Sanitize user input before logging to prevent PII exposure",
|
|
112
|
+
"filePatterns": ["**/api/**", "**/handlers/**"],
|
|
113
|
+
"reasoning": "Historical PII exposure issue - logging must use sanitized values"
|
|
114
|
+
}
|
|
115
|
+
</extracted-learning>
|
|
116
|
+
</example>
|
|
117
|
+
|
|
118
|
+
<example>
|
|
119
|
+
<ai-comment>
|
|
120
|
+
💡 MINOR: Consider using 'interface' instead of 'type' for object shapes.
|
|
121
|
+
</ai-comment>
|
|
122
|
+
<developer-reply>
|
|
123
|
+
We prefer 'type' for everything in this project - team decision.
|
|
124
|
+
</developer-reply>
|
|
125
|
+
<extracted-learning>
|
|
126
|
+
{
|
|
127
|
+
"category": "style_preference",
|
|
128
|
+
"subcategory": "TypeScript",
|
|
129
|
+
"learning": "Use 'type' over 'interface' for all type definitions",
|
|
130
|
+
"filePatterns": ["**/*.ts", "**/*.tsx"],
|
|
131
|
+
"reasoning": "Team convention to use type aliases consistently"
|
|
132
|
+
}
|
|
133
|
+
</extracted-learning>
|
|
134
|
+
</example>
|
|
135
|
+
</examples>
|
|
136
|
+
</yama-learning-system>
|
|
137
|
+
`;
|
|
138
|
+
/**
|
|
139
|
+
* Summarization prompt for consolidating knowledge base entries
|
|
140
|
+
*/
|
|
141
|
+
export const LEARNING_SUMMARIZATION_PROMPT = `
|
|
142
|
+
<yama-summarization-task>
|
|
143
|
+
<goal>Consolidate knowledge base learnings into concise, actionable guidelines</goal>
|
|
144
|
+
|
|
145
|
+
<instructions>
|
|
146
|
+
You will receive the current knowledge base content.
|
|
147
|
+
For each category section:
|
|
148
|
+
1. Identify duplicate or highly similar learnings
|
|
149
|
+
2. Merge related learnings into single statements
|
|
150
|
+
3. Keep the most general, actionable form
|
|
151
|
+
4. Preserve file patterns where applicable
|
|
152
|
+
5. Ensure no information is lost, just condensed
|
|
153
|
+
</instructions>
|
|
154
|
+
|
|
155
|
+
<rules>
|
|
156
|
+
- Combine learnings that say the same thing differently
|
|
157
|
+
- Keep specific technical details (don't over-generalize)
|
|
158
|
+
- Preserve all unique learnings
|
|
159
|
+
- Maintain subcategory organization
|
|
160
|
+
- Update the total count accurately
|
|
161
|
+
</rules>
|
|
162
|
+
|
|
163
|
+
<example>
|
|
164
|
+
Before:
|
|
165
|
+
- Don't flag Promise.all() in services
|
|
166
|
+
- Promise.all() is acceptable in async handlers
|
|
167
|
+
- Parallel Promise execution is intentional
|
|
168
|
+
|
|
169
|
+
After:
|
|
170
|
+
- Promise.all() for parallel async operations is acceptable across the codebase
|
|
171
|
+
</example>
|
|
172
|
+
|
|
173
|
+
<output-format>
|
|
174
|
+
Return the complete, updated knowledge base in markdown format.
|
|
175
|
+
Preserve the exact structure (headers, sections, metadata).
|
|
176
|
+
Update the metadata with new total count and summarization timestamp.
|
|
177
|
+
</output-format>
|
|
178
|
+
</yama-summarization-task>
|
|
179
|
+
`;
|
|
180
|
+
//# sourceMappingURL=LearningSystemPrompt.js.map
|
|
@@ -8,6 +8,8 @@
|
|
|
8
8
|
import { YamaV2Config } from "../types/config.types.js";
|
|
9
9
|
import { ReviewRequest } from "../types/v2.types.js";
|
|
10
10
|
export declare class PromptBuilder {
|
|
11
|
+
private langfuseManager;
|
|
12
|
+
constructor();
|
|
11
13
|
/**
|
|
12
14
|
* Build complete review instructions for AI
|
|
13
15
|
* Combines generic base prompt + project-specific config
|
|
@@ -26,6 +28,11 @@ export declare class PromptBuilder {
|
|
|
26
28
|
* Load project-specific standards from repository
|
|
27
29
|
*/
|
|
28
30
|
private loadProjectStandards;
|
|
31
|
+
/**
|
|
32
|
+
* Load knowledge base for AI prompt injection
|
|
33
|
+
* Contains learned patterns from previous PR feedback
|
|
34
|
+
*/
|
|
35
|
+
private loadKnowledgeBase;
|
|
29
36
|
/**
|
|
30
37
|
* Build description enhancement prompt separately (for description-only operations)
|
|
31
38
|
*/
|
|
@@ -8,20 +8,26 @@
|
|
|
8
8
|
import { readFile } from "fs/promises";
|
|
9
9
|
import { existsSync } from "fs";
|
|
10
10
|
import { join } from "path";
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
11
|
+
import { LangfusePromptManager } from "./LangfusePromptManager.js";
|
|
12
|
+
import { KnowledgeBaseManager } from "../learning/KnowledgeBaseManager.js";
|
|
13
13
|
export class PromptBuilder {
|
|
14
|
+
langfuseManager;
|
|
15
|
+
constructor() {
|
|
16
|
+
this.langfuseManager = new LangfusePromptManager();
|
|
17
|
+
}
|
|
14
18
|
/**
|
|
15
19
|
* Build complete review instructions for AI
|
|
16
20
|
* Combines generic base prompt + project-specific config
|
|
17
21
|
*/
|
|
18
22
|
async buildReviewInstructions(request, config) {
|
|
19
|
-
// Base system prompt
|
|
20
|
-
const basePrompt =
|
|
23
|
+
// Base system prompt - fetched from Langfuse or local fallback
|
|
24
|
+
const basePrompt = await this.langfuseManager.getReviewPrompt();
|
|
21
25
|
// Project-specific configuration in XML format
|
|
22
26
|
const projectConfig = this.buildProjectConfigXML(config, request);
|
|
23
27
|
// Project-specific standards (if available)
|
|
24
28
|
const projectStandards = await this.loadProjectStandards(config);
|
|
29
|
+
// Knowledge base learnings (reinforcement learning)
|
|
30
|
+
const knowledgeBase = await this.loadKnowledgeBase(config);
|
|
25
31
|
// Combine all parts
|
|
26
32
|
return `
|
|
27
33
|
${basePrompt}
|
|
@@ -32,6 +38,8 @@ ${projectConfig}
|
|
|
32
38
|
|
|
33
39
|
${projectStandards ? `<project-standards>\n${projectStandards}\n</project-standards>` : ""}
|
|
34
40
|
|
|
41
|
+
${knowledgeBase ? `<learned-knowledge>\n${knowledgeBase}\n</learned-knowledge>` : ""}
|
|
42
|
+
|
|
35
43
|
<review-task>
|
|
36
44
|
<workspace>${this.escapeXML(request.workspace)}</workspace>
|
|
37
45
|
<repository>${this.escapeXML(request.repository)}</repository>
|
|
@@ -67,7 +75,7 @@ ${projectStandards ? `<project-standards>\n${projectStandards}\n</project-standa
|
|
|
67
75
|
<description>${this.escapeXML(area.description)}</description>
|
|
68
76
|
</focus-area>`)
|
|
69
77
|
.join("\n");
|
|
70
|
-
const blockingCriteriaXML = config.review.blockingCriteria
|
|
78
|
+
const blockingCriteriaXML = (config.review.blockingCriteria || [])
|
|
71
79
|
.map((criteria) => `
|
|
72
80
|
<criterion>
|
|
73
81
|
<condition>${this.escapeXML(criteria.condition)}</condition>
|
|
@@ -157,12 +165,33 @@ Follow these in addition to the general focus areas:
|
|
|
157
165
|
${loadedStandards.join("\n\n---\n\n")}
|
|
158
166
|
`.trim();
|
|
159
167
|
}
|
|
168
|
+
/**
|
|
169
|
+
* Load knowledge base for AI prompt injection
|
|
170
|
+
* Contains learned patterns from previous PR feedback
|
|
171
|
+
*/
|
|
172
|
+
async loadKnowledgeBase(config) {
|
|
173
|
+
if (!config.knowledgeBase?.enabled) {
|
|
174
|
+
return null;
|
|
175
|
+
}
|
|
176
|
+
try {
|
|
177
|
+
const kbManager = new KnowledgeBaseManager(config.knowledgeBase);
|
|
178
|
+
const content = await kbManager.getForPrompt();
|
|
179
|
+
if (content) {
|
|
180
|
+
console.log(" 📚 Knowledge base loaded for AI context");
|
|
181
|
+
}
|
|
182
|
+
return content;
|
|
183
|
+
}
|
|
184
|
+
catch (error) {
|
|
185
|
+
// Silently fail - knowledge base is optional enhancement
|
|
186
|
+
return null;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
160
189
|
/**
|
|
161
190
|
* Build description enhancement prompt separately (for description-only operations)
|
|
162
191
|
*/
|
|
163
192
|
async buildDescriptionEnhancementInstructions(request, config) {
|
|
164
|
-
// Base enhancement prompt
|
|
165
|
-
const basePrompt =
|
|
193
|
+
// Base enhancement prompt - fetched from Langfuse or local fallback
|
|
194
|
+
const basePrompt = await this.langfuseManager.getEnhancementPrompt();
|
|
166
195
|
// Project-specific enhancement configuration
|
|
167
196
|
const enhancementConfigXML = this.buildEnhancementConfigXML(config);
|
|
168
197
|
return `
|
|
@@ -11,6 +11,7 @@ export interface YamaV2Config {
|
|
|
11
11
|
review: ReviewConfig;
|
|
12
12
|
descriptionEnhancement: DescriptionEnhancementConfig;
|
|
13
13
|
memoryBank: MemoryBankConfig;
|
|
14
|
+
knowledgeBase: KnowledgeBaseConfig;
|
|
14
15
|
projectStandards?: ProjectStandardsConfig;
|
|
15
16
|
monitoring: MonitoringConfig;
|
|
16
17
|
performance: PerformanceConfig;
|
|
@@ -48,15 +49,21 @@ export interface RedisConfig {
|
|
|
48
49
|
ttl?: number;
|
|
49
50
|
}
|
|
50
51
|
export interface MCPServersConfig {
|
|
52
|
+
bitbucket?: {
|
|
53
|
+
/** List of tool names to block from Bitbucket MCP server */
|
|
54
|
+
blockedTools?: string[];
|
|
55
|
+
};
|
|
51
56
|
jira: {
|
|
52
57
|
enabled: boolean;
|
|
58
|
+
/** List of tool names to block from Jira MCP server */
|
|
59
|
+
blockedTools?: string[];
|
|
53
60
|
};
|
|
54
61
|
}
|
|
55
62
|
export interface ReviewConfig {
|
|
56
63
|
enabled: boolean;
|
|
57
64
|
workflowInstructions: string;
|
|
58
65
|
focusAreas: FocusArea[];
|
|
59
|
-
blockingCriteria
|
|
66
|
+
blockingCriteria?: BlockingCriteria[];
|
|
60
67
|
excludePatterns: string[];
|
|
61
68
|
contextLines: number;
|
|
62
69
|
maxFilesPerReview: number;
|
|
@@ -90,6 +97,20 @@ export interface MemoryBankConfig {
|
|
|
90
97
|
fallbackPaths: string[];
|
|
91
98
|
standardFiles?: string[];
|
|
92
99
|
}
|
|
100
|
+
export interface KnowledgeBaseConfig {
|
|
101
|
+
/** Enable knowledge base feature */
|
|
102
|
+
enabled: boolean;
|
|
103
|
+
/** Path to knowledge base file (relative to project root) */
|
|
104
|
+
path: string;
|
|
105
|
+
/** Patterns to identify AI comment authors (case-insensitive) */
|
|
106
|
+
aiAuthorPatterns: string[];
|
|
107
|
+
/** Number of learnings before auto-summarization triggers */
|
|
108
|
+
maxEntriesBeforeSummarization: number;
|
|
109
|
+
/** Number of entries to retain after summarization */
|
|
110
|
+
summaryRetentionCount: number;
|
|
111
|
+
/** Auto-commit knowledge base changes (default for --commit flag) */
|
|
112
|
+
autoCommit: boolean;
|
|
113
|
+
}
|
|
93
114
|
export interface ProjectStandardsConfig {
|
|
94
115
|
customPromptsPath: string;
|
|
95
116
|
additionalFocusAreas: FocusArea[];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@juspay/yama",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "Enterprise-grade Pull Request automation toolkit with AI-powered code review and description enhancement",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pr",
|
|
@@ -83,7 +83,8 @@
|
|
|
83
83
|
"check:all": "npm run lint && npm run format --check && npm run validate && npm run validate:commit"
|
|
84
84
|
},
|
|
85
85
|
"dependencies": {
|
|
86
|
-
"@juspay/neurolink": "^8.1
|
|
86
|
+
"@juspay/neurolink": "^8.23.1",
|
|
87
|
+
"langfuse": "^3.35.0",
|
|
87
88
|
"@nexus2520/bitbucket-mcp-server": "^1.1.2",
|
|
88
89
|
"@nexus2520/jira-mcp-server": "^1.0.1",
|
|
89
90
|
"chalk": "^4.1.2",
|
|
@@ -150,7 +151,10 @@
|
|
|
150
151
|
"pnpm": {
|
|
151
152
|
"onlyBuiltDependencies": [
|
|
152
153
|
"esbuild"
|
|
153
|
-
]
|
|
154
|
+
],
|
|
155
|
+
"overrides": {
|
|
156
|
+
"@semantic-release/npm": "^13.1.2"
|
|
157
|
+
}
|
|
154
158
|
},
|
|
155
159
|
"lint-staged": {
|
|
156
160
|
"*.{ts,tsx,js,jsx}": [
|
package/yama.config.example.yaml
CHANGED
|
@@ -39,9 +39,25 @@ ai:
|
|
|
39
39
|
# ============================================================================
|
|
40
40
|
# Bitbucket MCP is always enabled (hardcoded)
|
|
41
41
|
# Jira MCP can be enabled/disabled here
|
|
42
|
+
# Use blockedTools to prevent AI from using specific MCP tools
|
|
42
43
|
mcpServers:
|
|
44
|
+
bitbucket:
|
|
45
|
+
# Optional: Block specific Bitbucket tools from AI access
|
|
46
|
+
# This prevents the AI from performing certain actions
|
|
47
|
+
blockedTools: []
|
|
48
|
+
# Example blocked tools (uncomment to use):
|
|
49
|
+
# - merge_pull_request # Prevent AI from merging PRs
|
|
50
|
+
# - delete_branch # Prevent AI from deleting branches
|
|
51
|
+
# - approve_pull_request # Prevent AI from auto-approving PRs
|
|
52
|
+
|
|
43
53
|
jira:
|
|
44
54
|
enabled: true # Set to false to disable Jira integration
|
|
55
|
+
# Optional: Block specific Jira tools from AI access
|
|
56
|
+
blockedTools: []
|
|
57
|
+
# Example blocked tools (uncomment to use):
|
|
58
|
+
# - jira_create_issue # Prevent AI from creating Jira issues
|
|
59
|
+
# - jira_delete_issue # Prevent AI from deleting issues
|
|
60
|
+
# - jira_update_issue # Prevent AI from modifying issues
|
|
45
61
|
|
|
46
62
|
# ============================================================================
|
|
47
63
|
# Review Configuration
|
|
@@ -89,19 +105,22 @@ review:
|
|
|
89
105
|
- Poor naming conventions
|
|
90
106
|
- Missing edge case handling
|
|
91
107
|
|
|
92
|
-
# Blocking criteria (AI uses these to decide whether to block PR)
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
108
|
+
# Blocking criteria (OPTIONAL - AI uses these to decide whether to block PR)
|
|
109
|
+
# If not provided or empty, AI will review and comment but NOT auto-block/approve PRs
|
|
110
|
+
# Uncomment and customize the examples below to enable auto-blocking:
|
|
111
|
+
blockingCriteria: []
|
|
112
|
+
# blockingCriteria:
|
|
113
|
+
# - condition: "ANY CRITICAL severity issue"
|
|
114
|
+
# action: "BLOCK"
|
|
115
|
+
# reason: "Security or data loss risk"
|
|
116
|
+
#
|
|
117
|
+
# - condition: "3 or more MAJOR severity issues"
|
|
118
|
+
# action: "BLOCK"
|
|
119
|
+
# reason: "Too many significant bugs/performance issues"
|
|
120
|
+
#
|
|
121
|
+
# - condition: "Jira requirement coverage < 70%"
|
|
122
|
+
# action: "BLOCK"
|
|
123
|
+
# reason: "Incomplete implementation of requirements"
|
|
105
124
|
|
|
106
125
|
# Files to exclude from analysis
|
|
107
126
|
excludePatterns:
|
|
@@ -183,6 +202,32 @@ memoryBank:
|
|
|
183
202
|
- "coding-standards.md"
|
|
184
203
|
- "security-guidelines.md"
|
|
185
204
|
|
|
205
|
+
# ============================================================================
|
|
206
|
+
# Knowledge Base - Reinforcement Learning from PR Feedback
|
|
207
|
+
# ============================================================================
|
|
208
|
+
# Yama learns from developer feedback on AI comments across merged PRs.
|
|
209
|
+
# Use 'yama learn -w <workspace> -r <repo> -p <pr-id>' to extract learnings.
|
|
210
|
+
knowledgeBase:
|
|
211
|
+
enabled: true
|
|
212
|
+
|
|
213
|
+
# Path to knowledge base file (relative to repo root)
|
|
214
|
+
path: ".yama/knowledge-base.md"
|
|
215
|
+
|
|
216
|
+
# Patterns to identify AI-generated comments (author name matching)
|
|
217
|
+
aiAuthorPatterns:
|
|
218
|
+
- "Yama"
|
|
219
|
+
- "yama-bot"
|
|
220
|
+
- "yama-review"
|
|
221
|
+
|
|
222
|
+
# Automatically summarize knowledge base when entry count exceeds this
|
|
223
|
+
maxEntriesBeforeSummarization: 50
|
|
224
|
+
|
|
225
|
+
# How many consolidated entries to keep after summarization
|
|
226
|
+
summaryRetentionCount: 20
|
|
227
|
+
|
|
228
|
+
# Automatically commit knowledge base changes (with --commit flag)
|
|
229
|
+
autoCommit: false
|
|
230
|
+
|
|
186
231
|
# ============================================================================
|
|
187
232
|
# Project-Specific Standards (Override in your repository)
|
|
188
233
|
# ============================================================================
|