@juspay/yama 2.4.2 → 2.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.
@@ -123,10 +123,29 @@ export class MemoryManager {
123
123
  };
124
124
  }
125
125
  /**
126
- * Build a deterministic owner ID from workspace and repository.
126
+ * Build a deterministic owner ID from provider, workspace, and repository.
127
+ * Isolates memory per platform to prevent collisions between same repo names
128
+ * on different platforms (e.g., "repo" on GitHub vs Bitbucket).
129
+ *
130
+ * Format:
131
+ * - GitHub: github-{owner}-{repo}
132
+ * - Bitbucket: bitbucket-{workspace}-{repo}
133
+ *
127
134
  * This value is passed as `context.userId` in generate() calls.
128
135
  */
129
- static buildOwnerId(workspace, repository) {
136
+ static buildOwnerId(workspace, repository, provider = "bitbucket") {
137
+ const providerPrefix = provider.toLowerCase();
138
+ return `${providerPrefix}-${workspace}-${repository}`.toLowerCase();
139
+ }
140
+ /**
141
+ * Build the legacy (unprefixed) owner ID used before provider isolation.
142
+ *
143
+ * Format: {workspace}-{repository}
144
+ *
145
+ * Used as a read-time fallback so memory written before the provider-prefix
146
+ * upgrade keeps working. New writes always use the provider-prefixed key.
147
+ */
148
+ static buildLegacyOwnerId(workspace, repository) {
130
149
  return `${workspace}-${repository}`.toLowerCase();
131
150
  }
132
151
  /**
@@ -146,10 +165,16 @@ export class MemoryManager {
146
165
  }
147
166
  }
148
167
  /**
149
- * Read persisted condensed memory for a workspace/repository pair.
168
+ * Read persisted condensed memory for a workspace/repository pair on a specific provider.
150
169
  */
151
- async readRepositoryMemory(workspace, repository) {
152
- return this.readMemory(MemoryManager.buildOwnerId(workspace, repository));
170
+ async readRepositoryMemory(workspace, repository, provider = "bitbucket") {
171
+ const prefixed = await this.readMemory(MemoryManager.buildOwnerId(workspace, repository, provider));
172
+ if (prefixed !== null) {
173
+ return prefixed;
174
+ }
175
+ // Fall back to the legacy unprefixed key so memory written before the
176
+ // provider-prefix upgrade is not silently dropped after upgrading.
177
+ return this.readMemory(MemoryManager.buildLegacyOwnerId(workspace, repository));
153
178
  }
154
179
  /**
155
180
  * Commit memory files to the repository if autoCommit is enabled.
@@ -8,14 +8,22 @@
8
8
  import { YamaConfig } from "../types/config.types.js";
9
9
  import { LocalReviewRequest, ReviewRequest } from "../types/v2.types.js";
10
10
  import type { LocalDiffContext } from "../core/LocalDiffSource.js";
11
+ import { type VCSProviderName } from "../providers/ProviderToolset.js";
11
12
  export declare class PromptBuilder {
12
13
  private langfuseManager;
13
14
  constructor();
15
+ /**
16
+ * Build the provider-agnostic params object the ProviderToolset consumes.
17
+ * Carries both Bitbucket (workspace/repository/pullRequestId) and GitHub
18
+ * (owner/repo/prNumber) identifiers plus the shared branch; each toolset
19
+ * reads only the fields it needs.
20
+ */
21
+ private toToolsetParams;
14
22
  /**
15
23
  * Build complete review instructions for AI
16
24
  * Combines generic base prompt + project-specific config
17
25
  */
18
- buildReviewInstructions(request: ReviewRequest, config: YamaConfig, bootstrapStandards?: string | null): Promise<string>;
26
+ buildReviewInstructions(request: ReviewRequest, config: YamaConfig, bootstrapStandards: string | null | undefined, provider: VCSProviderName): Promise<string>;
19
27
  /**
20
28
  * Per-PR workflow block. Standards-first, file-by-file, explore-on-uncertainty.
21
29
  * The agent stays autonomous; this just choreographs the order it should follow.
@@ -54,7 +62,7 @@ export declare class PromptBuilder {
54
62
  /**
55
63
  * Build description enhancement prompt separately (for description-only operations)
56
64
  */
57
- buildDescriptionEnhancementInstructions(request: ReviewRequest, config: YamaConfig): Promise<string>;
65
+ buildDescriptionEnhancementInstructions(request: ReviewRequest, config: YamaConfig, provider: VCSProviderName): Promise<string>;
58
66
  /**
59
67
  * Build local SDK review instructions.
60
68
  * Produces strict JSON output for local diff quality analysis.
@@ -9,19 +9,73 @@ import { readFile } from "fs/promises";
9
9
  import { existsSync } from "fs";
10
10
  import { join } from "path";
11
11
  import { LangfusePromptManager } from "./LangfusePromptManager.js";
12
+ import { buildReviewSystemPrompt } from "./ReviewSystemPrompt.js";
12
13
  import { KnowledgeBaseManager } from "../learning/KnowledgeBaseManager.js";
14
+ import { getProviderToolset, } from "../providers/ProviderToolset.js";
13
15
  export class PromptBuilder {
14
16
  langfuseManager;
15
17
  constructor() {
16
18
  this.langfuseManager = new LangfusePromptManager();
17
19
  }
20
+ /**
21
+ * Build the provider-agnostic params object the ProviderToolset consumes.
22
+ * Carries both Bitbucket (workspace/repository/pullRequestId) and GitHub
23
+ * (owner/repo/prNumber) identifiers plus the shared branch; each toolset
24
+ * reads only the fields it needs.
25
+ */
26
+ toToolsetParams(request) {
27
+ const params = {};
28
+ const workspace = (request.workspace || "").trim();
29
+ const repository = (request.repository || "").trim();
30
+ const branch = (request.branch || "N/A").trim();
31
+ params.workspace = workspace;
32
+ params.repository = repository;
33
+ params.branch = branch;
34
+ // Coalesce the PR identifier across both field names so the toolset always
35
+ // receives the PR number regardless of which one the caller populated.
36
+ // GitHub's identifierXml reads params.prNumber while Bitbucket's reads
37
+ // params.pullRequestId; CLI callers set request.pullRequestId even for
38
+ // GitHub, so without this a GitHub run would lose the PR number and fall
39
+ // back to 'find-by-branch'. No-op for existing Bitbucket behavior.
40
+ const resolvedPrNumber = request.prNumber ??
41
+ (typeof request.pullRequestId === "number"
42
+ ? request.pullRequestId
43
+ : undefined);
44
+ const resolvedPullRequestId = request.pullRequestId ?? request.prNumber;
45
+ if (resolvedPullRequestId !== undefined) {
46
+ params.pullRequestId = resolvedPullRequestId;
47
+ }
48
+ if (request.owner !== undefined) {
49
+ params.owner = request.owner.trim();
50
+ }
51
+ // Coalesce the repo name across the GitHub-specific 'repo' field and the
52
+ // shared 'repository' field, mirroring the prNumber<->pullRequestId
53
+ // coalescing above. A GitHub caller may populate the shared 'repository'
54
+ // field instead of 'repo'; without this the toolset would receive GitHub
55
+ // identifiers with no repo name. No-op for existing Bitbucket behavior,
56
+ // which never sets request.repo.
57
+ const resolvedRepo = request.repo ?? request.repository;
58
+ if (resolvedRepo !== undefined) {
59
+ params.repo = resolvedRepo.trim();
60
+ }
61
+ if (resolvedPrNumber !== undefined) {
62
+ params.prNumber = resolvedPrNumber;
63
+ }
64
+ return params;
65
+ }
18
66
  /**
19
67
  * Build complete review instructions for AI
20
68
  * Combines generic base prompt + project-specific config
21
69
  */
22
- async buildReviewInstructions(request, config, bootstrapStandards) {
23
- // Base system prompt - fetched from Langfuse or local fallback
24
- const basePromptRaw = await this.langfuseManager.getReviewPrompt();
70
+ async buildReviewInstructions(request, config, bootstrapStandards, provider) {
71
+ const toolset = getProviderToolset(provider);
72
+ // Base system prompt. Prefer a Langfuse-managed prompt when one is
73
+ // configured (provider-agnostic remote override); otherwise fall back to
74
+ // the provider-aware local prompt so the <tool-usage> section matches the
75
+ // active provider's tool idiom.
76
+ const basePromptRaw = this.langfuseManager.isEnabled()
77
+ ? await this.langfuseManager.getReviewPrompt()
78
+ : buildReviewSystemPrompt(toolset);
25
79
  // Project-specific configuration in XML format
26
80
  const projectConfig = this.buildProjectConfigXML(config, request);
27
81
  // Project-specific standards (if available)
@@ -31,7 +85,8 @@ export class PromptBuilder {
31
85
  const exploreEnabled = config.ai.explore.enabled;
32
86
  // Strip explore_context references when the subagent is disabled.
33
87
  const basePrompt = PromptBuilder.stripDisabledSections(basePromptRaw, exploreEnabled);
34
- const workflowBlock = PromptBuilder.stripDisabledSections(this.buildReviewWorkflow(request), exploreEnabled);
88
+ const toolsetParams = this.toToolsetParams(request);
89
+ const workflowBlock = PromptBuilder.stripDisabledSections(this.buildReviewWorkflow(request, toolset, toolsetParams), exploreEnabled);
35
90
  const bootstrapBlock = bootstrapStandards && bootstrapStandards.trim().length > 0
36
91
  ? `<bootstrapped-standards>
37
92
  <!--
@@ -59,10 +114,7 @@ ${bootstrapBlock}
59
114
  ${knowledgeBase ? `<learned-knowledge>\n${knowledgeBase}\n</learned-knowledge>` : ""}
60
115
 
61
116
  <review-task>
62
- <workspace>${this.escapeXML(request.workspace)}</workspace>
63
- <repository>${this.escapeXML(request.repository)}</repository>
64
- <pull_request_id>${request.pullRequestId || "find-by-branch"}</pull_request_id>
65
- <branch>${this.escapeXML(request.branch || "N/A")}</branch>
117
+ ${toolset.identifierXml(toolsetParams)}
66
118
  <mode>${request.dryRun ? "dry-run" : "live"}</mode>
67
119
 
68
120
  ${workflowBlock}
@@ -73,47 +125,18 @@ ${workflowBlock}
73
125
  * Per-PR workflow block. Standards-first, file-by-file, explore-on-uncertainty.
74
126
  * The agent stays autonomous; this just choreographs the order it should follow.
75
127
  */
76
- buildReviewWorkflow(request) {
128
+ buildReviewWorkflow(request, toolset, params) {
77
129
  const modeLine = request.dryRun
78
130
  ? "DRY RUN MODE: simulate actions only, do not post real comments or change PR state."
79
131
  : "LIVE MODE: post real comments and make real decisions.";
80
132
  const additional = request.prompt
81
133
  ? `\n ADDITIONAL INSTRUCTIONS: ${this.escapeXML(request.prompt)}`
82
134
  : "";
135
+ // The numbered review steps (tool names + workflow prose) come from the
136
+ // provider toolset; the <instructions> wrapper and the dynamic mode/
137
+ // additional tail stay here so they apply to every provider unchanged.
83
138
  return ` <instructions>
84
- Begin your autonomous review. Follow this order.
85
-
86
- STEP 1 — Read project standards
87
- Read the <project-standards> block above carefully. Treat any reviewer-expectation
88
- entry with severity=BLOCKING as a blocking criterion for this PR. If the block is
89
- missing or empty, fall back to <focus-areas> and <blocking-criteria>.
90
-
91
- STEP 2 — Read the PR shell
92
- Call get_pull_request once to get changed files, branch info, and existing comments.
93
- Build a mental map of which files exist and which already have comments.
94
- Do NOT request the full PR diff.
95
-
96
- STEP 3 — Walk files one at a time
97
- For each changed file, in order:
98
- a. Call get_pull_request_diff(file_path=&lt;this file&gt;).
99
- b. Cross-check the diff against project-standards and existing comments on this file.
100
- c. If anything is non-trivial — multi-file impact, unfamiliar pattern, unclear intent,
101
- history-dependent behavior — <!-- EXPLORE_BEGIN -->call explore_context with a precise
102
- task and wait for its evidence before commenting<!-- EXPLORE_END --><!-- EXPLORE_DISABLED_BEGIN -->use search_code or get_file_content to verify before commenting<!-- EXPLORE_DISABLED_END -->.
103
- d. For every confirmed issue, call add_comment immediately with line_number and
104
- line_type from the diff JSON. Include a real-code suggestion for CRITICAL/MAJOR.
105
- e. Move to the next file. Never request another file's diff before finishing the
106
- current one. Never request a multi-file diff.
107
-
108
- STEP 4 — Decision
109
- After the last file, count issues by severity, apply <blocking-criteria>, and call
110
- set_pr_approval(approved=true) OR set_review_status(request_changes=true).
111
-
112
- STEP 5 — Summary comment
113
- Post one summary comment with file count, issue counts by severity, and next steps.
114
-
115
- Budget guidance: roughly 10 tool calls per file in the main loop. If you exceed
116
- that on a single file, <!-- EXPLORE_BEGIN -->delegate the rest to explore_context<!-- EXPLORE_END --><!-- EXPLORE_DISABLED_BEGIN -->stop investigating<!-- EXPLORE_DISABLED_END --> and move on.
139
+ ${toolset.reviewWorkflowInstructions(params)}
117
140
 
118
141
  ${modeLine}${additional}
119
142
  </instructions>`;
@@ -298,7 +321,9 @@ ${loadedStandards.join("\n\n---\n\n")}
298
321
  /**
299
322
  * Build description enhancement prompt separately (for description-only operations)
300
323
  */
301
- async buildDescriptionEnhancementInstructions(request, config) {
324
+ async buildDescriptionEnhancementInstructions(request, config, provider) {
325
+ const toolset = getProviderToolset(provider);
326
+ const toolsetParams = this.toToolsetParams(request);
302
327
  // Base enhancement prompt - fetched from Langfuse or local fallback
303
328
  const basePrompt = await this.langfuseManager.getEnhancementPrompt();
304
329
  // Project-specific enhancement configuration
@@ -311,25 +336,11 @@ ${enhancementConfigXML}
311
336
  </project-configuration>
312
337
 
313
338
  <enhancement-task>
314
- <workspace>${this.escapeXML(request.workspace)}</workspace>
315
- <repository>${this.escapeXML(request.repository)}</repository>
316
- <pull_request_id>${request.pullRequestId || "find-by-branch"}</pull_request_id>
317
- <branch>${this.escapeXML(request.branch || "N/A")}</branch>
339
+ ${toolset.identifierXml(toolsetParams)}
318
340
  <mode>${request.dryRun ? "dry-run" : "live"}</mode>
319
341
 
320
342
  <instructions>
321
- Enhance the PR description now.
322
-
323
- 1. Call get_pull_request() to read current PR and description
324
- 2. Call get_pull_request_diff() to analyze code changes
325
- 3. Use search_code() to find configuration patterns, API changes
326
- 4. Extract information for each required section
327
- 5. Build enhanced description following section structure
328
- 6. Call update_pull_request() with enhanced description
329
-
330
- CRITICAL: Return ONLY the enhanced description markdown.
331
- Do NOT include meta-commentary or explanations.
332
- Start directly with section content.
343
+ ${toolset.descriptionEnhancementInstructions(toolsetParams)}
333
344
 
334
345
  ${request.dryRun ? "DRY RUN MODE: Simulate only, do not actually update PR." : "LIVE MODE: Update the actual PR description."}
335
346
  ${request.prompt ? `ADDITIONAL INSTRUCTIONS: ${this.escapeXML(request.prompt)}` : ""}
@@ -7,7 +7,35 @@
7
7
  *
8
8
  * Sections wrapped in <!-- EXPLORE_BEGIN --> ... <!-- EXPLORE_END --> markers
9
9
  * are stripped by PromptBuilder when config.ai.explore.enabled is false.
10
+ *
11
+ * The <tool-usage> section is the ONLY provider-specific part of this prompt.
12
+ * It is supplied by the ProviderToolset so the same review philosophy, severity
13
+ * rules and anti-patterns drive both Bitbucket and GitHub. For
14
+ * provider === "bitbucket" the rendered output is byte-identical to the
15
+ * historical hardcoded prompt (the toolset's Bitbucket strings were copied
16
+ * verbatim).
17
+ */
18
+ import { type ProviderToolset, type VCSProviderName } from "../providers/ProviderToolset.js";
19
+ /**
20
+ * Render the base review system prompt for a given provider.
21
+ *
22
+ * Accepts either a provider name (the common case) or an already-resolved
23
+ * ProviderToolset. Only the <tool-usage> section varies by provider; every
24
+ * other block (identity, core rules, severity levels, anti-patterns) is shared
25
+ * verbatim.
26
+ */
27
+ export declare function buildReviewSystemPrompt(provider: VCSProviderName | ProviderToolset): string;
28
+ /**
29
+ * Provider-aware alias matching the pinned signature `build(provider)`.
30
+ */
31
+ export declare const build: typeof buildReviewSystemPrompt;
32
+ /**
33
+ * Bitbucket-rendered base review system prompt.
34
+ *
35
+ * Kept as a named constant for backward compatibility with consumers that
36
+ * expect a static fallback (e.g. LangfusePromptManager's Bitbucket fallback).
37
+ * This is byte-identical to the historical hardcoded prompt.
10
38
  */
11
- export declare const REVIEW_SYSTEM_PROMPT = "\n<yama-review-system>\n <identity>\n <role>Autonomous Code Review Agent</role>\n <authority>Read code, post inline comments, approve or request changes on a PR.</authority>\n </identity>\n\n <core-rules>\n <rule id=\"standards-first\">Read the &lt;project-standards&gt; block in your task before touching any file. Treat reviewer-expectation entries with severity=BLOCKING as blocking criteria for the PR.</rule>\n <rule id=\"verify-before-comment\">Never comment on code you don't understand. Use search_code or get_file_content for cheap, single-shot lookups.<!-- EXPLORE_BEGIN --> Use explore_context whenever the investigation is broader than a single tool call, spans multiple files, or depends on history.<!-- EXPLORE_END --></rule>\n <rule id=\"file-by-file\">Process exactly one file at a time. Get its diff, analyze it fully, post all comments for it, then move on. Never request another file's diff before finishing the current file. Never request a full multi-file PR diff.</rule>\n <rule id=\"accurate-commenting\">Inline comments use line_number and line_type taken directly from the diff JSON: ADDED \u2192 destination_line, REMOVED \u2192 source_line, CONTEXT \u2192 destination_line.</rule>\n <rule id=\"comment-immediately\">Post comments as you find issues. Do not batch them until the end.</rule>\n <rule id=\"avoid-duplicates\">Check existing comments before posting. If a developer's reply is wrong, reply to it instead of duplicating.</rule>\n </core-rules>\n\n <tool-usage>\n <tool name=\"get_pull_request\">\n <use-when>Once at the start, to read PR metadata and existing comments.</use-when>\n </tool>\n\n <tool name=\"get_pull_request_diff\">\n <use-when>For ONE file at a time, immediately before reviewing it.</use-when>\n <do-not-use-when>Never call this without a file_path argument. Never request the full PR diff.</do-not-use-when>\n </tool>\n\n <tool name=\"search_code\">\n <use-when>A single direct lookup answers your question (function definition, single file).</use-when>\n <do-not-use-when>The investigation needs more than one call or spans multiple files \u2014 delegate to explore_context instead.</do-not-use-when>\n </tool>\n\n <tool name=\"get_file_content\">\n <use-when>You already know the path and need the file's contents.</use-when>\n </tool>\n\n <!-- EXPLORE_BEGIN -->\n <tool name=\"explore_context\">\n <use-when>Multi-step research, multi-file tracing, history lookup, ambiguous behavior, or anything that would otherwise need 3+ tool calls in the main loop.</use-when>\n <do-not-use-when>A single search_code or get_file_content would answer it. Delegating cheap lookups wastes a turn.</do-not-use-when>\n <how>Pass a one-sentence research question as task and optional file paths/PR refs as focus. The subagent returns evidence-backed findings; trust the evidence, and if it's empty, do not comment on that area.</how>\n <example positive>Diff adds a retry guard in PaymentProcessor \u2192 explore_context(task=\"Is this retry guard consistent with how other payment handlers retry, and does it match the convention from PR 842?\", focus=[\"src/payments/\", \"PR 842\"])</example>\n <example negative>Don't: explore_context(task=\"What does validatePayment do?\"). Do: search_code(search_query=\"function validatePayment\").</example>\n </tool>\n <!-- EXPLORE_END -->\n\n <tool name=\"add_comment\">\n <fields>file_path, line_number, line_type (ADDED|REMOVED|CONTEXT), comment_text, and suggestion (required for CRITICAL and MAJOR \u2014 must be real, executable code).</fields>\n <do-not-use-when>You only have a code_snippet but no line_number/line_type from the diff JSON.</do-not-use-when>\n </tool>\n\n <tool name=\"set_pr_approval\">\n <use-when>No blocking issues found. Pass approved=true.</use-when>\n </tool>\n\n <tool name=\"set_review_status\">\n <use-when>Blocking criteria met. Pass request_changes=true.</use-when>\n </tool>\n </tool-usage>\n\n <severity-levels>\n <level name=\"CRITICAL\" emoji=\"\uD83D\uDD12\">Blocks the PR. MUST include a real-code suggestion. Security, data loss, auth flaws, hardcoded secrets.</level>\n <level name=\"MAJOR\" emoji=\"\u26A0\uFE0F\">Blocks if multiple. MUST include a real-code suggestion. Logic bugs, perf issues, broken APIs.</level>\n <level name=\"MINOR\" emoji=\"\uD83D\uDCA1\">Request changes. Suggestion optional. Quality, naming, duplication.</level>\n <level name=\"SUGGESTION\" emoji=\"\uD83D\uDCAC\">Informational. Optimizations and improvements.</level>\n </severity-levels>\n\n <anti-patterns>\n <dont>Request all files upfront \u2014 use lazy loading, one file at a time.</dont>\n <dont>Batch comments until the end \u2014 comment immediately as you find issues.</dont>\n <dont>Assume what code does \u2014 verify with tools first.</dont>\n <dont>Use a code_snippet field \u2014 always use line_number and line_type from the diff JSON.</dont>\n <dont>Jump between files \u2014 finish one file before starting another.</dont>\n <dont>Duplicate an existing comment \u2014 check first; reply if a developer's response is wrong.</dont>\n </anti-patterns>\n</yama-review-system>\n";
39
+ export declare const REVIEW_SYSTEM_PROMPT: string;
12
40
  export default REVIEW_SYSTEM_PROMPT;
13
41
  //# sourceMappingURL=ReviewSystemPrompt.d.ts.map
@@ -7,8 +7,27 @@
7
7
  *
8
8
  * Sections wrapped in <!-- EXPLORE_BEGIN --> ... <!-- EXPLORE_END --> markers
9
9
  * are stripped by PromptBuilder when config.ai.explore.enabled is false.
10
+ *
11
+ * The <tool-usage> section is the ONLY provider-specific part of this prompt.
12
+ * It is supplied by the ProviderToolset so the same review philosophy, severity
13
+ * rules and anti-patterns drive both Bitbucket and GitHub. For
14
+ * provider === "bitbucket" the rendered output is byte-identical to the
15
+ * historical hardcoded prompt (the toolset's Bitbucket strings were copied
16
+ * verbatim).
17
+ */
18
+ import { getProviderToolset, } from "../providers/ProviderToolset.js";
19
+ /**
20
+ * Render the base review system prompt for a given provider.
21
+ *
22
+ * Accepts either a provider name (the common case) or an already-resolved
23
+ * ProviderToolset. Only the <tool-usage> section varies by provider; every
24
+ * other block (identity, core rules, severity levels, anti-patterns) is shared
25
+ * verbatim.
10
26
  */
11
- export const REVIEW_SYSTEM_PROMPT = `
27
+ export function buildReviewSystemPrompt(provider) {
28
+ const toolset = typeof provider === "string" ? getProviderToolset(provider) : provider;
29
+ const toolUsageSection = toolset.systemPromptToolsSection();
30
+ return `
12
31
  <yama-review-system>
13
32
  <identity>
14
33
  <role>Autonomous Code Review Agent</role>
@@ -24,48 +43,7 @@ export const REVIEW_SYSTEM_PROMPT = `
24
43
  <rule id="avoid-duplicates">Check existing comments before posting. If a developer's reply is wrong, reply to it instead of duplicating.</rule>
25
44
  </core-rules>
26
45
 
27
- <tool-usage>
28
- <tool name="get_pull_request">
29
- <use-when>Once at the start, to read PR metadata and existing comments.</use-when>
30
- </tool>
31
-
32
- <tool name="get_pull_request_diff">
33
- <use-when>For ONE file at a time, immediately before reviewing it.</use-when>
34
- <do-not-use-when>Never call this without a file_path argument. Never request the full PR diff.</do-not-use-when>
35
- </tool>
36
-
37
- <tool name="search_code">
38
- <use-when>A single direct lookup answers your question (function definition, single file).</use-when>
39
- <do-not-use-when>The investigation needs more than one call or spans multiple files — delegate to explore_context instead.</do-not-use-when>
40
- </tool>
41
-
42
- <tool name="get_file_content">
43
- <use-when>You already know the path and need the file's contents.</use-when>
44
- </tool>
45
-
46
- <!-- EXPLORE_BEGIN -->
47
- <tool name="explore_context">
48
- <use-when>Multi-step research, multi-file tracing, history lookup, ambiguous behavior, or anything that would otherwise need 3+ tool calls in the main loop.</use-when>
49
- <do-not-use-when>A single search_code or get_file_content would answer it. Delegating cheap lookups wastes a turn.</do-not-use-when>
50
- <how>Pass a one-sentence research question as task and optional file paths/PR refs as focus. The subagent returns evidence-backed findings; trust the evidence, and if it's empty, do not comment on that area.</how>
51
- <example positive>Diff adds a retry guard in PaymentProcessor → explore_context(task="Is this retry guard consistent with how other payment handlers retry, and does it match the convention from PR 842?", focus=["src/payments/", "PR 842"])</example>
52
- <example negative>Don't: explore_context(task="What does validatePayment do?"). Do: search_code(search_query="function validatePayment").</example>
53
- </tool>
54
- <!-- EXPLORE_END -->
55
-
56
- <tool name="add_comment">
57
- <fields>file_path, line_number, line_type (ADDED|REMOVED|CONTEXT), comment_text, and suggestion (required for CRITICAL and MAJOR — must be real, executable code).</fields>
58
- <do-not-use-when>You only have a code_snippet but no line_number/line_type from the diff JSON.</do-not-use-when>
59
- </tool>
60
-
61
- <tool name="set_pr_approval">
62
- <use-when>No blocking issues found. Pass approved=true.</use-when>
63
- </tool>
64
-
65
- <tool name="set_review_status">
66
- <use-when>Blocking criteria met. Pass request_changes=true.</use-when>
67
- </tool>
68
- </tool-usage>
46
+ ${toolUsageSection}
69
47
 
70
48
  <severity-levels>
71
49
  <level name="CRITICAL" emoji="🔒">Blocks the PR. MUST include a real-code suggestion. Security, data loss, auth flaws, hardcoded secrets.</level>
@@ -84,5 +62,18 @@ export const REVIEW_SYSTEM_PROMPT = `
84
62
  </anti-patterns>
85
63
  </yama-review-system>
86
64
  `;
65
+ }
66
+ /**
67
+ * Provider-aware alias matching the pinned signature `build(provider)`.
68
+ */
69
+ export const build = buildReviewSystemPrompt;
70
+ /**
71
+ * Bitbucket-rendered base review system prompt.
72
+ *
73
+ * Kept as a named constant for backward compatibility with consumers that
74
+ * expect a static fallback (e.g. LangfusePromptManager's Bitbucket fallback).
75
+ * This is byte-identical to the historical hardcoded prompt.
76
+ */
77
+ export const REVIEW_SYSTEM_PROMPT = buildReviewSystemPrompt("bitbucket");
87
78
  export default REVIEW_SYSTEM_PROMPT;
88
79
  //# sourceMappingURL=ReviewSystemPrompt.js.map
@@ -0,0 +1,54 @@
1
+ /**
2
+ * ProviderToolset — the single source of truth for everything that differs
3
+ * between VCS providers (Bitbucket vs GitHub) when Yama drives an AI review.
4
+ *
5
+ * Every provider-specific string the AI sees (the <available_tools> section,
6
+ * the numbered review workflow, the PR-context identifier block, the
7
+ * description-enhancement steps) and every provider-specific signal Yama reads
8
+ * back (which tool call is a comment, a diff fetch, a repo mutation, or an
9
+ * approve/block decision) lives behind this interface.
10
+ *
11
+ * The Bitbucket toolset reproduces the CURRENT prompt wording verbatim, so
12
+ * behaviour for Bitbucket stays byte-identical. The GitHub toolset teaches the
13
+ * official github/github-mcp-server consolidated API and pending-review flow,
14
+ * keeping the same review philosophy and severity rules.
15
+ */
16
+ export type VCSProviderName = "github" | "bitbucket";
17
+ export interface ReviewPromptParams {
18
+ workspace?: string;
19
+ repository?: string;
20
+ pullRequestId?: number | string;
21
+ owner?: string;
22
+ repo?: string;
23
+ prNumber?: number;
24
+ branch?: string;
25
+ }
26
+ export interface ProviderToolCall {
27
+ toolName?: string;
28
+ args?: Record<string, unknown>;
29
+ }
30
+ export interface ProviderToolset {
31
+ readonly provider: VCSProviderName;
32
+ /** Tool name the AI calls to read a PR's metadata/comments
33
+ * (Bitbucket: get_pull_request; GitHub: pull_request_read). */
34
+ readonly prReadToolName: string;
35
+ /** <pr_context> identifier block injected into review/enhancement prompts */
36
+ identifierXml(params: ReviewPromptParams): string;
37
+ /** The <available_tools> section listing the tools the AI may call (provider idiom) */
38
+ systemPromptToolsSection(): string;
39
+ /** Provider-specific numbered review workflow instructions (prose the AI follows) */
40
+ reviewWorkflowInstructions(params: ReviewPromptParams): string;
41
+ /** Provider-specific PR-description-enhancement workflow instructions */
42
+ descriptionEnhancementInstructions(params: ReviewPromptParams): string;
43
+ /** Tool names whose calls represent an inline/PR comment (statistics counting) */
44
+ readonly commentToolNames: string[];
45
+ /** Tool names representing diff/file retrieval (statistics counting) */
46
+ readonly diffToolNames: string[];
47
+ /** Plain tool names that mutate PR/repo state (explore_context block list) */
48
+ readonly mutationToolNames: string[];
49
+ /** Interpret a single tool call as an approve/block decision signal, else null.
50
+ * Bitbucket: set_pr_approval/set_review_status (+ args). GitHub: pull_request_review_write with args.event. */
51
+ interpretDecision(call: ProviderToolCall): "APPROVED" | "BLOCKED" | null;
52
+ }
53
+ export declare function getProviderToolset(provider: VCSProviderName): ProviderToolset;
54
+ //# sourceMappingURL=ProviderToolset.d.ts.map