@juspay/yama 1.5.1 → 1.6.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 CHANGED
@@ -1,3 +1,9 @@
1
+ # [1.6.0](https://github.com/juspay/yama/compare/v1.5.1...v1.6.0) (2025-10-24)
2
+
3
+ ### Features
4
+
5
+ - added support for system prompt and fixed required section check in description enhancer ([c22d1ff](https://github.com/juspay/yama/commit/c22d1ff15a165379dece65145123433f7c1d6b98))
6
+
1
7
  ## [1.5.1](https://github.com/juspay/yama/compare/v1.5.0...v1.5.1) (2025-09-24)
2
8
 
3
9
  ### Bug Fixes
@@ -59,7 +59,13 @@ export class Guardian {
59
59
  fallbackPaths: ["docs/memory-bank", ".memory-bank"],
60
60
  });
61
61
  this.codeReviewer = new CodeReviewer(this.bitbucketProvider, this.config.providers.ai, this.config.features.codeReview);
62
- this.descriptionEnhancer = new DescriptionEnhancer(this.bitbucketProvider, this.config.providers.ai);
62
+ this.descriptionEnhancer = new DescriptionEnhancer(this.bitbucketProvider, this.config.providers.ai, this.config.features.descriptionEnhancement);
63
+ logger.debug("Description Enhancement Configuration:");
64
+ logger.debug(` - Enabled: ${this.config.features.descriptionEnhancement.enabled}`);
65
+ logger.debug(` - Required Sections: ${this.config.features.descriptionEnhancement.requiredSections.length} (${this.config.features.descriptionEnhancement.requiredSections.map((s) => s.key).join(", ")})`);
66
+ logger.debug(` - Custom systemPrompt: ${this.config.features.descriptionEnhancement.systemPrompt ? "Yes" : "No (using default)"}`);
67
+ logger.debug(` - Custom enhancementInstructions: ${this.config.features.descriptionEnhancement.enhancementInstructions ? "Yes" : "No (using default)"}`);
68
+ logger.debug(` - outputTemplate: ${this.config.features.descriptionEnhancement.outputTemplate ? "Provided" : "Not provided"}`);
63
69
  this.initialized = true;
64
70
  logger.success("✅ Yama initialized successfully");
65
71
  }
@@ -2,15 +2,21 @@
2
2
  * Enhanced Description Enhancer - Optimized to work with Unified Context
3
3
  * Preserves all original functionality from pr-describe.js but optimized
4
4
  */
5
- import { EnhancementOptions, EnhancementResult, AIProviderConfig } from "../types/index.js";
5
+ import { EnhancementOptions, EnhancementResult, AIProviderConfig, DescriptionEnhancementConfig } from "../types/index.js";
6
6
  import { UnifiedContext } from "../core/ContextGatherer.js";
7
7
  import { BitbucketProvider } from "../core/providers/BitbucketProvider.js";
8
8
  export declare class DescriptionEnhancer {
9
9
  private neurolink;
10
10
  private bitbucketProvider;
11
11
  private aiConfig;
12
+ private enhancementConfig;
12
13
  private defaultRequiredSections;
13
- constructor(bitbucketProvider: BitbucketProvider, aiConfig: AIProviderConfig);
14
+ constructor(bitbucketProvider: BitbucketProvider, aiConfig: AIProviderConfig, enhancementConfig: DescriptionEnhancementConfig);
15
+ /**
16
+ * Get system prompt for description enhancement
17
+ * Uses config.systemPrompt if provided, otherwise uses default
18
+ */
19
+ private getSystemPrompt;
14
20
  /**
15
21
  * Enhance description using pre-gathered unified context (OPTIMIZED)
16
22
  */
@@ -60,5 +66,5 @@ export declare class DescriptionEnhancer {
60
66
  */
61
67
  getStats(): any;
62
68
  }
63
- export declare function createDescriptionEnhancer(bitbucketProvider: BitbucketProvider, aiConfig: AIProviderConfig): DescriptionEnhancer;
69
+ export declare function createDescriptionEnhancer(bitbucketProvider: BitbucketProvider, aiConfig: AIProviderConfig, enhancementConfig: DescriptionEnhancementConfig): DescriptionEnhancer;
64
70
  //# sourceMappingURL=DescriptionEnhancer.d.ts.map
@@ -8,6 +8,7 @@ export class DescriptionEnhancer {
8
8
  neurolink;
9
9
  bitbucketProvider;
10
10
  aiConfig;
11
+ enhancementConfig;
11
12
  defaultRequiredSections = [
12
13
  { key: "changelog", name: "Changelog (Modules Modified)", required: true },
13
14
  {
@@ -21,9 +22,33 @@ export class DescriptionEnhancer {
21
22
  required: true,
22
23
  },
23
24
  ];
24
- constructor(bitbucketProvider, aiConfig) {
25
+ constructor(bitbucketProvider, aiConfig, enhancementConfig) {
25
26
  this.bitbucketProvider = bitbucketProvider;
26
27
  this.aiConfig = aiConfig;
28
+ this.enhancementConfig = enhancementConfig;
29
+ }
30
+ /**
31
+ * Get system prompt for description enhancement
32
+ * Uses config.systemPrompt if provided, otherwise uses default
33
+ */
34
+ getSystemPrompt() {
35
+ const isCustomPrompt = !!this.enhancementConfig.systemPrompt;
36
+ if (isCustomPrompt) {
37
+ logger.debug("✓ Using custom systemPrompt from configuration");
38
+ logger.debug(`Custom prompt preview: ${this.enhancementConfig.systemPrompt?.substring(0, 100)}...`);
39
+ }
40
+ else {
41
+ logger.debug("Using default systemPrompt (no custom prompt configured)");
42
+ }
43
+ return (this.enhancementConfig.systemPrompt ||
44
+ `You are an Expert Technical Writer specializing in pull request documentation.
45
+ Focus on clarity, completeness, and helping reviewers understand the changes.
46
+
47
+ CRITICAL INSTRUCTION: Return ONLY the enhanced PR description content.
48
+ - DO NOT add meta-commentary like "No description provided" or "Here is the enhanced description"
49
+ - DO NOT add explanatory text about what you're doing
50
+ - START directly with the actual PR content (title, sections, etc.)
51
+ - If there's no existing description, just write the new sections without mentioning it`);
27
52
  }
28
53
  /**
29
54
  * Enhance description using pre-gathered unified context (OPTIMIZED)
@@ -34,7 +59,21 @@ export class DescriptionEnhancer {
34
59
  logger.phase("📝 Enhancing PR description...");
35
60
  logger.info(`Processing PR #${context.pr.id}: "${context.pr.title}"`);
36
61
  // Step 1: Analyze existing content and identify what needs enhancement
37
- const analysisResult = this.analyzeExistingContent(context.pr.description, options.customSections || this.defaultRequiredSections);
62
+ const sectionsToUse = options.customSections || this.defaultRequiredSections;
63
+ logger.debug(`Checking ${sectionsToUse.length} required sections: ${sectionsToUse.map((s) => s.key).join(", ")}`);
64
+ const analysisResult = this.analyzeExistingContent(context.pr.description, sectionsToUse);
65
+ const presentSections = analysisResult.requiredSections
66
+ .filter((s) => s.present)
67
+ .map((s) => s.key);
68
+ const missingSections = analysisResult.requiredSections
69
+ .filter((s) => !s.present)
70
+ .map((s) => s.key);
71
+ if (presentSections.length > 0) {
72
+ logger.debug(`✓ Present sections: ${presentSections.join(", ")}`);
73
+ }
74
+ if (missingSections.length > 0) {
75
+ logger.debug(`✗ Missing sections: ${missingSections.join(", ")}`);
76
+ }
38
77
  logger.info(`Content analysis: ${analysisResult.preservedContent.media.length} media items, ` +
39
78
  `${analysisResult.missingCount} missing sections`);
40
79
  // Step 2: Generate enhanced description using AI
@@ -135,15 +174,21 @@ export class DescriptionEnhancer {
135
174
  ],
136
175
  };
137
176
  return requiredSections.map((section) => {
138
- const patterns = sectionPatterns[section.key];
139
- const isPresent = patterns
140
- ? patterns.some((pattern) => pattern.test(description))
141
- : false;
177
+ let patterns = sectionPatterns[section.key];
178
+ if (!patterns) {
179
+ logger.debug(`No predefined pattern for section "${section.key}", using dynamic pattern based on name`);
180
+ const nameWords = section.name.split(/\s+/).filter((w) => w.length > 2); // Filter out short words like "Or", "Of"
181
+ const namePattern = new RegExp(`##.*?${nameWords.join(".*?")}`, "i");
182
+ const keyWords = section.key.split("_").filter((w) => w.length > 2);
183
+ const keyPattern = new RegExp(`##.*?${keyWords.join(".*?")}`, "i");
184
+ patterns = [namePattern, keyPattern];
185
+ }
186
+ const isPresent = patterns.some((pattern) => pattern.test(description));
142
187
  return {
143
188
  ...section,
144
189
  present: isPresent,
145
190
  content: isPresent
146
- ? this.extractSectionContent(description, patterns || [])
191
+ ? this.extractSectionContent(description, patterns)
147
192
  : "",
148
193
  };
149
194
  });
@@ -207,6 +252,7 @@ export class DescriptionEnhancer {
207
252
  try {
208
253
  const result = await this.neurolink.generate({
209
254
  input: { text: enhancementPrompt },
255
+ systemPrompt: this.getSystemPrompt(), // Use config or default system prompt
210
256
  provider: this.aiConfig.provider,
211
257
  model: this.aiConfig.model,
212
258
  temperature: this.aiConfig.temperature || 0.7,
@@ -224,6 +270,13 @@ export class DescriptionEnhancer {
224
270
  .replace(/^```markdown\s*/, "")
225
271
  .replace(/\s*```$/, "")
226
272
  .trim();
273
+ // Remove any meta-commentary that AI might have added
274
+ enhancedDescription = enhancedDescription
275
+ .replace(/^No description provided\.?\s*/i, "")
276
+ .replace(/^Here is the enhanced description:?\s*/i, "")
277
+ .replace(/^I will enhance.*?:\s*/i, "")
278
+ .replace(/^Enhanced description:?\s*/i, "")
279
+ .trim();
227
280
  if (!enhancedDescription) {
228
281
  throw new Error("AI generated empty description");
229
282
  }
@@ -231,7 +284,12 @@ export class DescriptionEnhancer {
231
284
  const finalValidation = this.validateRequiredSections(enhancedDescription, options.customSections || this.defaultRequiredSections);
232
285
  const stillMissing = finalValidation.filter((s) => !s.present);
233
286
  if (stillMissing.length > 0) {
234
- logger.warn(`Warning: ${stillMissing.length} required sections still missing after AI enhancement`);
287
+ const missingSectionNames = stillMissing.map((s) => s.key).join(", ");
288
+ logger.warn(`Warning: ${stillMissing.length} required sections still missing after AI enhancement: ${missingSectionNames}`);
289
+ logger.debug(`AI may not have added these sections or they don't match detection patterns`);
290
+ }
291
+ else {
292
+ logger.debug(`✓ All ${finalValidation.length} required sections are now present`);
235
293
  }
236
294
  return enhancedDescription;
237
295
  }
@@ -260,7 +318,15 @@ export class DescriptionEnhancer {
260
318
  diffInfo = `**Diff Strategy**: File-by-file analysis (${context.diffStrategy.fileCount} files)
261
319
  **Modified Files**: ${JSON.stringify(fileList, null, 2)}`;
262
320
  }
263
- return `You are an expert technical writer specializing in comprehensive PR descriptions.
321
+ const customInstructions = this.enhancementConfig.enhancementInstructions || "";
322
+ if (customInstructions) {
323
+ logger.debug("✓ Using custom enhancementInstructions from configuration");
324
+ logger.debug(`Instructions preview: ${customInstructions.substring(0, 80)}...`);
325
+ }
326
+ else {
327
+ logger.debug("Using default enhancementInstructions");
328
+ }
329
+ return `${customInstructions || "You are an expert technical writer specializing in comprehensive PR descriptions."}
264
330
 
265
331
  ## PR INFORMATION:
266
332
  **Title**: ${context.pr.title}
@@ -439,7 +505,7 @@ Generate the enhanced description now, ensuring ALL preservation requirements ar
439
505
  };
440
506
  }
441
507
  }
442
- export function createDescriptionEnhancer(bitbucketProvider, aiConfig) {
443
- return new DescriptionEnhancer(bitbucketProvider, aiConfig);
508
+ export function createDescriptionEnhancer(bitbucketProvider, aiConfig, enhancementConfig) {
509
+ return new DescriptionEnhancer(bitbucketProvider, aiConfig, enhancementConfig);
444
510
  }
445
511
  //# sourceMappingURL=DescriptionEnhancer.js.map
@@ -80,7 +80,7 @@ export class ConfigManager {
80
80
  },
81
81
  ],
82
82
  autoFormat: true,
83
- systemPrompt: "You are an Expert Technical Writer specializing in pull request documentation. Your role is to:\n\n📝 CLARITY FIRST: Create clear, comprehensive PR descriptions that help reviewers understand the changes\n🎥 STORY TELLING: Explain the 'why' behind changes, not just the 'what'\n📈 STRUCTURED: Follow consistent formatting with required sections\n🔗 CONTEXTUAL: Link changes to business value and technical rationale\n\nCRITICAL INSTRUCTION: Return ONLY the enhanced PR description content as clean markdown. Do NOT include any meta-commentary, explanations about what you're doing, or introductory text like \"I will enhance...\" or \"Here is the enhanced description:\". \n\nOutput the enhanced description directly without any wrapper text or explanations.",
83
+ systemPrompt: "You are an Expert Technical Writer specializing in pull request documentation. Your role is to:\n\n📝 CLARITY FIRST: Create clear, comprehensive PR descriptions that help reviewers understand the changes\n🎥 STORY TELLING: Explain the 'why' behind changes, not just the 'what'\n📈 STRUCTURED: Follow consistent formatting with required sections\n🔗 CONTEXTUAL: Link changes to business value and technical rationale\n\nCRITICAL INSTRUCTION: Return ONLY the enhanced PR description content as clean markdown.\n- DO NOT add meta-commentary like \"No description provided\" or \"Here is the enhanced description\"\n- DO NOT add explanatory text about what you're doing\n- START directly with the actual PR content (sections, lists, explanations)\n- If there's no existing description, just write the new sections without mentioning it\n\nOutput the enhanced description directly without any wrapper text or explanations.",
84
84
  outputTemplate: "# PR Title Enhancement (if needed)\n\n## Summary\n[Clear overview of what this PR accomplishes]\n\n## Changes Made\n[Specific technical changes - be precise]\n\n## Testing\n[How the changes were tested]\n\n## Impact\n[Business/technical impact and considerations]\n\n## Additional Notes\n[Any deployment notes, follow-ups, or special considerations]",
85
85
  enhancementInstructions: 'Return ONLY the enhanced PR description as clean markdown. Do NOT include any explanatory text, meta-commentary, or phrases like "Here is the enhanced description:" or "I will enhance...".\n\nStart directly with the enhanced description content using this structure:',
86
86
  },
@@ -244,11 +244,10 @@ export class ConfigManager {
244
244
  * Apply provider-aware token limits using shared utility
245
245
  */
246
246
  applyProviderTokenLimits(config) {
247
- const provider = config.providers.ai.provider || 'auto';
247
+ const provider = config.providers.ai.provider || "auto";
248
248
  const configuredTokens = config.providers.ai.maxTokens;
249
249
  // Use the shared utility to validate and adjust token limits
250
- const validatedTokens = validateProviderTokenLimit(provider, configuredTokens, false // Use standard limits for configuration
251
- );
250
+ const validatedTokens = validateProviderTokenLimit(provider, configuredTokens, false);
252
251
  config.providers.ai.maxTokens = validatedTokens;
253
252
  return config;
254
253
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@juspay/yama",
3
- "version": "1.5.1",
3
+ "version": "1.6.0",
4
4
  "description": "Enterprise-grade Pull Request automation toolkit with AI-powered code review and description enhancement",
5
5
  "keywords": [
6
6
  "pr",
@@ -109,6 +109,7 @@ features:
109
109
  enabled: true
110
110
  preserveContent: true # Always preserve existing content
111
111
  autoFormat: true
112
+
112
113
  requiredSections:
113
114
  - key: "changelog"
114
115
  name: "Changelog (Modules Modified)"
@@ -120,6 +121,16 @@ features:
120
121
  name: "CAC Config Or Service Config Changes"
121
122
  required: true
122
123
 
124
+ # Customize AI behavior:
125
+ systemPrompt: |
126
+ You are a Senior Staff Engineer writing comprehensive technical documentation.
127
+ Focus on architectural decisions, trade-offs, and long-term maintainability.
128
+
129
+ # Customize formatting:
130
+ enhancementInstructions: |
131
+ Keep descriptions under 300 words. Use bullet points, not paragraphs.
132
+ No emojis. Professional tone only. Include numbers and metrics.
133
+
123
134
  # NEW: Diff Strategy Configuration
124
135
  diffStrategy:
125
136
  enabled: true