@j0hanz/code-review-analyst-mcp 1.7.0 → 1.7.1
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/README.md +21 -13
- package/dist/lib/diff-store.d.ts +1 -0
- package/dist/lib/diff-store.js +2 -0
- package/dist/lib/gemini.js +3 -1
- package/dist/lib/model-config.d.ts +13 -15
- package/dist/lib/model-config.js +16 -25
- package/dist/lib/tool-contracts.d.ts +9 -9
- package/dist/lib/tool-contracts.js +9 -9
- package/dist/lib/tool-factory.d.ts +17 -11
- package/dist/lib/tool-factory.js +63 -108
- package/dist/resources/index.js +1 -1
- package/dist/resources/instructions.js +1 -1
- package/dist/resources/tool-catalog.js +2 -2
- package/dist/tools/analyze-complexity.js +0 -1
- package/dist/tools/analyze-pr-impact.js +0 -1
- package/dist/tools/detect-api-breaking.js +0 -1
- package/dist/tools/generate-review-summary.js +0 -1
- package/dist/tools/generate-test-plan.js +0 -1
- package/dist/tools/inspect-code-quality.js +0 -1
- package/dist/tools/suggest-search-replace.js +0 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -12,13 +12,13 @@ Gemini-powered MCP server for pull request analysis with structured outputs for
|
|
|
12
12
|
|
|
13
13
|
## Overview
|
|
14
14
|
|
|
15
|
-
This server accepts unified diffs and returns structured JSON results — findings with severity, impact categories, merge risk, test plans, and verbatim search/replace fixes. It uses Gemini Thinking models (Flash for fast tools,
|
|
15
|
+
This server accepts unified diffs and returns structured JSON results — findings with severity, impact categories, merge risk, test plans, and verbatim search/replace fixes. It uses Gemini Thinking models (Flash for fast tools, Flash for deep analysis) and runs over **stdio transport**.
|
|
16
16
|
|
|
17
17
|
## Key Features
|
|
18
18
|
|
|
19
19
|
- **Impact Analysis** — Objective severity scoring, breaking change detection, and rollback complexity assessment.
|
|
20
20
|
- **Review Summary** — Concise PR digest with merge recommendation and change statistics.
|
|
21
|
-
- **Deep Code Inspection** —
|
|
21
|
+
- **Deep Code Inspection** — Flash model with high thinking level for context-aware analysis using full file contents.
|
|
22
22
|
- **Search & Replace Fixes** — Verbatim, copy-paste-ready code fixes tied to specific findings.
|
|
23
23
|
- **Test Plan Generation** — Systematic test case generation with priority ranking and pseudocode.
|
|
24
24
|
- **Async Task Support** — All tools support MCP task lifecycle with progress notifications.
|
|
@@ -279,13 +279,25 @@ docker build -t code-review-analyst-mcp .
|
|
|
279
279
|
|
|
280
280
|
## Tools
|
|
281
281
|
|
|
282
|
+
> [!IMPORTANT]
|
|
283
|
+
> Call `generate_diff` first (`mode: "unstaged"` or `"staged"`). All review tools read the cached server-side diff (`diff://current`) and do not accept a direct `diff` parameter.
|
|
284
|
+
|
|
285
|
+
### `generate_diff`
|
|
286
|
+
|
|
287
|
+
Generate and cache the current branch diff for downstream review tools.
|
|
288
|
+
|
|
289
|
+
| Parameter | Type | Required | Description |
|
|
290
|
+
| --------- | -------- | -------- | -------------------------------------------------- |
|
|
291
|
+
| `mode` | `string` | Yes | `unstaged` (working tree) or `staged` (git index). |
|
|
292
|
+
|
|
293
|
+
**Returns:** `diffRef`, `stats` (files, added, deleted), `generatedAt`, `mode`, `message`.
|
|
294
|
+
|
|
282
295
|
### `analyze_pr_impact`
|
|
283
296
|
|
|
284
|
-
Assess the impact and risk of
|
|
297
|
+
Assess the impact and risk of cached pull request changes using the Flash model.
|
|
285
298
|
|
|
286
299
|
| Parameter | Type | Required | Description |
|
|
287
300
|
| ------------ | -------- | -------- | ---------------------------------------- |
|
|
288
|
-
| `diff` | `string` | Yes | Unified diff text. |
|
|
289
301
|
| `repository` | `string` | Yes | Repository identifier (e.g. `org/repo`). |
|
|
290
302
|
| `language` | `string` | No | Primary language hint. |
|
|
291
303
|
|
|
@@ -297,7 +309,6 @@ Summarize a pull request diff and assess high-level risk using the Flash model.
|
|
|
297
309
|
|
|
298
310
|
| Parameter | Type | Required | Description |
|
|
299
311
|
| ------------ | -------- | -------- | ---------------------------------------- |
|
|
300
|
-
| `diff` | `string` | Yes | Unified diff text. |
|
|
301
312
|
| `repository` | `string` | Yes | Repository identifier (e.g. `org/repo`). |
|
|
302
313
|
| `language` | `string` | No | Primary language hint. |
|
|
303
314
|
|
|
@@ -305,11 +316,10 @@ Summarize a pull request diff and assess high-level risk using the Flash model.
|
|
|
305
316
|
|
|
306
317
|
### `inspect_code_quality`
|
|
307
318
|
|
|
308
|
-
Deep-dive code review using the
|
|
319
|
+
Deep-dive code review using the Flash model with high thinking (16K token budget).
|
|
309
320
|
|
|
310
321
|
| Parameter | Type | Required | Description |
|
|
311
322
|
| ------------- | ---------- | -------- | --------------------------------------------- |
|
|
312
|
-
| `diff` | `string` | Yes | Unified diff text. |
|
|
313
323
|
| `repository` | `string` | Yes | Repository identifier (e.g. `org/repo`). |
|
|
314
324
|
| `language` | `string` | No | Primary language hint. |
|
|
315
325
|
| `focusAreas` | `string[]` | No | Areas to inspect: security, correctness, etc. |
|
|
@@ -322,11 +332,10 @@ Deep-dive code review using the Pro model with thinking (16K token budget).
|
|
|
322
332
|
|
|
323
333
|
### `suggest_search_replace`
|
|
324
334
|
|
|
325
|
-
Generate verbatim search-and-replace blocks to fix a specific finding using the
|
|
335
|
+
Generate verbatim search-and-replace blocks to fix a specific finding using the Flash model with high thinking.
|
|
326
336
|
|
|
327
337
|
| Parameter | Type | Required | Description |
|
|
328
338
|
| ---------------- | -------- | -------- | ---------------------------------------- |
|
|
329
|
-
| `diff` | `string` | Yes | Unified diff that contains the issue. |
|
|
330
339
|
| `findingTitle` | `string` | Yes | Short title of the finding to fix. |
|
|
331
340
|
| `findingDetails` | `string` | Yes | Detailed explanation of the bug or risk. |
|
|
332
341
|
|
|
@@ -338,7 +347,6 @@ Create a test plan covering the changes in the diff using the Flash model with t
|
|
|
338
347
|
|
|
339
348
|
| Parameter | Type | Required | Description |
|
|
340
349
|
| --------------- | -------- | -------- | ------------------------------------------- |
|
|
341
|
-
| `diff` | `string` | Yes | Unified diff to generate tests for. |
|
|
342
350
|
| `repository` | `string` | Yes | Repository identifier (e.g. `org/repo`). |
|
|
343
351
|
| `language` | `string` | No | Primary language hint. |
|
|
344
352
|
| `testFramework` | `string` | No | Test framework (e.g. jest, vitest, pytest). |
|
|
@@ -391,8 +399,8 @@ Create a test plan covering the changes in the diff using the Flash model with t
|
|
|
391
399
|
| ------------------------- | ------------------------ | -------------- |
|
|
392
400
|
| `analyze_pr_impact` | `gemini-3-flash-preview` | `minimal` |
|
|
393
401
|
| `generate_review_summary` | `gemini-3-flash-preview` | `minimal` |
|
|
394
|
-
| `inspect_code_quality` | `gemini-3-
|
|
395
|
-
| `suggest_search_replace` | `gemini-3-
|
|
402
|
+
| `inspect_code_quality` | `gemini-3-flash-preview` | `high` |
|
|
403
|
+
| `suggest_search_replace` | `gemini-3-flash-preview` | `high` |
|
|
396
404
|
| `generate_test_plan` | `gemini-3-flash-preview` | `medium` |
|
|
397
405
|
|
|
398
406
|
## Workflows
|
|
@@ -456,7 +464,7 @@ The pipeline runs lint, type-check, test, and build, then publishes to three tar
|
|
|
456
464
|
| ------------------------------------------ | ------------------------------------------------------------------------------------ |
|
|
457
465
|
| `Missing GEMINI_API_KEY or GOOGLE_API_KEY` | Set one of the API key env vars in your MCP client config. |
|
|
458
466
|
| `E_INPUT_TOO_LARGE` | Diff exceeds budget. Split into smaller diffs. |
|
|
459
|
-
| `Gemini request timed out` |
|
|
467
|
+
| `Gemini request timed out` | Deep analysis tasks may take 60-120s. Increase your client timeout. |
|
|
460
468
|
| `Too many concurrent Gemini calls` | Reduce parallel tool calls or increase `MAX_CONCURRENT_CALLS`. |
|
|
461
469
|
| No tool output visible | Ensure your MCP client is not swallowing `stderr` — the server uses stdio transport. |
|
|
462
470
|
|
package/dist/lib/diff-store.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
|
2
2
|
import type { ParsedFile } from './diff.js';
|
|
3
3
|
import { createErrorToolResponse } from './tool-response.js';
|
|
4
4
|
export declare const DIFF_RESOURCE_URI = "diff://current";
|
|
5
|
+
export declare const diffStaleWarningMs: import("./env-config.js").CachedEnvInt;
|
|
5
6
|
export interface DiffStats {
|
|
6
7
|
files: number;
|
|
7
8
|
added: number;
|
package/dist/lib/diff-store.js
CHANGED
|
@@ -3,6 +3,8 @@ import { createErrorToolResponse } from './tool-response.js';
|
|
|
3
3
|
export const DIFF_RESOURCE_URI = 'diff://current';
|
|
4
4
|
const diffCacheTtlMs = createCachedEnvInt('DIFF_CACHE_TTL_MS', 60 * 60 * 1_000 // 1 hour default
|
|
5
5
|
);
|
|
6
|
+
export const diffStaleWarningMs = createCachedEnvInt('DIFF_STALE_WARNING_MS', 5 * 60 * 1_000 // 5 minutes default
|
|
7
|
+
);
|
|
6
8
|
const diffSlots = new Map();
|
|
7
9
|
let sendResourceUpdated;
|
|
8
10
|
function setDiffSlot(key, data) {
|
package/dist/lib/gemini.js
CHANGED
|
@@ -39,6 +39,7 @@ const TRUE_ENV_VALUES = new Set(['1', 'true', 'yes', 'on']);
|
|
|
39
39
|
const FALSE_ENV_VALUES = new Set(['0', 'false', 'no', 'off']);
|
|
40
40
|
const SLEEP_UNREF_OPTIONS = { ref: false };
|
|
41
41
|
const JSON_CODE_BLOCK_PATTERN = /```(?:json)?\n?([\s\S]*?)(?=\n?```)/u;
|
|
42
|
+
const NEVER_ABORT_SIGNAL = new AbortController().signal;
|
|
42
43
|
const maxConcurrentCallsConfig = createCachedEnvInt('MAX_CONCURRENT_CALLS', 10);
|
|
43
44
|
const maxConcurrentBatchCallsConfig = createCachedEnvInt('MAX_CONCURRENT_BATCH_CALLS', 2);
|
|
44
45
|
const concurrencyWaitMsConfig = createCachedEnvInt('MAX_CONCURRENT_CALLS_WAIT_MS', 2_000);
|
|
@@ -746,12 +747,13 @@ async function runInlineBatchWithPolling(request, model, onLog) {
|
|
|
746
747
|
let completed = false;
|
|
747
748
|
let timedOut = false;
|
|
748
749
|
try {
|
|
750
|
+
const createSignal = request.signal ?? NEVER_ABORT_SIGNAL;
|
|
749
751
|
const createPayload = {
|
|
750
752
|
model,
|
|
751
753
|
src: [
|
|
752
754
|
{
|
|
753
755
|
contents: [{ role: 'user', parts: [{ text: request.prompt }] }],
|
|
754
|
-
config: buildGenerationConfig(request,
|
|
756
|
+
config: buildGenerationConfig(request, createSignal),
|
|
755
757
|
},
|
|
756
758
|
],
|
|
757
759
|
};
|
|
@@ -1,34 +1,32 @@
|
|
|
1
1
|
/** Fast, cost-effective model for summarization and light analysis. */
|
|
2
2
|
export declare const FLASH_MODEL = "gemini-3-flash-preview";
|
|
3
|
-
/** High-capability model for deep reasoning, quality inspection, and reliable code generation. */
|
|
4
|
-
export declare const PRO_MODEL = "gemini-3-pro-preview";
|
|
5
3
|
/** Default language hint. */
|
|
6
4
|
export declare const DEFAULT_LANGUAGE = "detect";
|
|
7
5
|
/** Default test-framework hint. */
|
|
8
6
|
export declare const DEFAULT_FRAMEWORK = "detect";
|
|
9
|
-
/** Extended timeout for
|
|
10
|
-
export declare const
|
|
7
|
+
/** Extended timeout for deep analysis calls (ms). */
|
|
8
|
+
export declare const DEFAULT_TIMEOUT_EXTENDED_MS = 120000;
|
|
11
9
|
export declare const MODEL_TIMEOUT_MS: {
|
|
12
|
-
readonly
|
|
10
|
+
readonly extended: 120000;
|
|
13
11
|
};
|
|
14
12
|
/** Thinking level for Flash triage. */
|
|
15
13
|
export declare const FLASH_TRIAGE_THINKING_LEVEL: "minimal";
|
|
16
14
|
/** Thinking level for Flash analysis. */
|
|
17
15
|
export declare const FLASH_THINKING_LEVEL: "medium";
|
|
18
|
-
/** Thinking level for
|
|
19
|
-
export declare const
|
|
16
|
+
/** Thinking level for Flash deep analysis. */
|
|
17
|
+
export declare const FLASH_HIGH_THINKING_LEVEL: "high";
|
|
20
18
|
/** Output cap for Flash API breaking-change detection. */
|
|
21
|
-
export declare const FLASH_API_BREAKING_MAX_OUTPUT_TOKENS
|
|
19
|
+
export declare const FLASH_API_BREAKING_MAX_OUTPUT_TOKENS = 65536;
|
|
22
20
|
/** Output cap for Flash complexity analysis. */
|
|
23
|
-
export declare const FLASH_COMPLEXITY_MAX_OUTPUT_TOKENS
|
|
21
|
+
export declare const FLASH_COMPLEXITY_MAX_OUTPUT_TOKENS = 65536;
|
|
24
22
|
/** Output cap for Flash test-plan generation. */
|
|
25
|
-
export declare const FLASH_TEST_PLAN_MAX_OUTPUT_TOKENS
|
|
23
|
+
export declare const FLASH_TEST_PLAN_MAX_OUTPUT_TOKENS = 65536;
|
|
26
24
|
/** Output cap for Flash triage tools. */
|
|
27
|
-
export declare const FLASH_TRIAGE_MAX_OUTPUT_TOKENS
|
|
28
|
-
/** Output cap for
|
|
29
|
-
export declare const
|
|
30
|
-
/** Output cap for
|
|
31
|
-
export declare const
|
|
25
|
+
export declare const FLASH_TRIAGE_MAX_OUTPUT_TOKENS = 65536;
|
|
26
|
+
/** Output cap for Flash patch generation. */
|
|
27
|
+
export declare const FLASH_PATCH_MAX_OUTPUT_TOKENS = 65536;
|
|
28
|
+
/** Output cap for Flash deep review findings. */
|
|
29
|
+
export declare const FLASH_REVIEW_MAX_OUTPUT_TOKENS = 65536;
|
|
32
30
|
/** Temperature for analytical tools. */
|
|
33
31
|
export declare const ANALYSIS_TEMPERATURE: 1;
|
|
34
32
|
/** Temperature for creative synthesis (test plans). */
|
package/dist/lib/model-config.js
CHANGED
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
/** Fast, cost-effective model for summarization and light analysis. */
|
|
2
2
|
export const FLASH_MODEL = 'gemini-3-flash-preview';
|
|
3
|
-
/** High-capability model for deep reasoning, quality inspection, and reliable code generation. */
|
|
4
|
-
export const PRO_MODEL = 'gemini-3-pro-preview';
|
|
5
3
|
/** Default language hint. */
|
|
6
4
|
export const DEFAULT_LANGUAGE = 'detect';
|
|
7
5
|
/** Default test-framework hint. */
|
|
8
6
|
export const DEFAULT_FRAMEWORK = 'detect';
|
|
9
|
-
/** Extended timeout for
|
|
10
|
-
export const
|
|
7
|
+
/** Extended timeout for deep analysis calls (ms). */
|
|
8
|
+
export const DEFAULT_TIMEOUT_EXTENDED_MS = 120_000;
|
|
11
9
|
export const MODEL_TIMEOUT_MS = {
|
|
12
|
-
|
|
10
|
+
extended: DEFAULT_TIMEOUT_EXTENDED_MS,
|
|
13
11
|
};
|
|
14
12
|
Object.freeze(MODEL_TIMEOUT_MS);
|
|
15
13
|
// ---------------------------------------------------------------------------
|
|
@@ -21,35 +19,28 @@ const THINKING_LEVELS = {
|
|
|
21
19
|
/** Medium thinking for analysis tasks. */
|
|
22
20
|
flash: 'medium',
|
|
23
21
|
/** High thinking for deep review and patches. */
|
|
24
|
-
|
|
25
|
-
};
|
|
26
|
-
// Thinking budget in tokens for Flash and Pro tools. Note that these are not hard limits, but rather guidelines to encourage concise responses and manage latency/cost.
|
|
27
|
-
const OUTPUT_TOKEN_BUDGET = {
|
|
28
|
-
flashApiBreaking: 4_096,
|
|
29
|
-
flashComplexity: 4_096,
|
|
30
|
-
flashTestPlan: 8_192,
|
|
31
|
-
flashTriage: 4_096,
|
|
32
|
-
proPatch: 8_192,
|
|
33
|
-
proReview: 12_288,
|
|
22
|
+
flashHigh: 'high',
|
|
34
23
|
};
|
|
35
24
|
/** Thinking level for Flash triage. */
|
|
36
25
|
export const FLASH_TRIAGE_THINKING_LEVEL = THINKING_LEVELS.flashTriage;
|
|
37
26
|
/** Thinking level for Flash analysis. */
|
|
38
27
|
export const FLASH_THINKING_LEVEL = THINKING_LEVELS.flash;
|
|
39
|
-
/** Thinking level for
|
|
40
|
-
export const
|
|
28
|
+
/** Thinking level for Flash deep analysis. */
|
|
29
|
+
export const FLASH_HIGH_THINKING_LEVEL = THINKING_LEVELS.flashHigh;
|
|
30
|
+
// Output token caps for various tools. Set to a high default to avoid cutting off important information, but can be adjusted as needed.
|
|
31
|
+
const DEFAULT_OUTPUT_CAP = 65_536;
|
|
41
32
|
/** Output cap for Flash API breaking-change detection. */
|
|
42
|
-
export const FLASH_API_BREAKING_MAX_OUTPUT_TOKENS =
|
|
33
|
+
export const FLASH_API_BREAKING_MAX_OUTPUT_TOKENS = DEFAULT_OUTPUT_CAP;
|
|
43
34
|
/** Output cap for Flash complexity analysis. */
|
|
44
|
-
export const FLASH_COMPLEXITY_MAX_OUTPUT_TOKENS =
|
|
35
|
+
export const FLASH_COMPLEXITY_MAX_OUTPUT_TOKENS = DEFAULT_OUTPUT_CAP;
|
|
45
36
|
/** Output cap for Flash test-plan generation. */
|
|
46
|
-
export const FLASH_TEST_PLAN_MAX_OUTPUT_TOKENS =
|
|
37
|
+
export const FLASH_TEST_PLAN_MAX_OUTPUT_TOKENS = DEFAULT_OUTPUT_CAP;
|
|
47
38
|
/** Output cap for Flash triage tools. */
|
|
48
|
-
export const FLASH_TRIAGE_MAX_OUTPUT_TOKENS =
|
|
49
|
-
/** Output cap for
|
|
50
|
-
export const
|
|
51
|
-
/** Output cap for
|
|
52
|
-
export const
|
|
39
|
+
export const FLASH_TRIAGE_MAX_OUTPUT_TOKENS = DEFAULT_OUTPUT_CAP;
|
|
40
|
+
/** Output cap for Flash patch generation. */
|
|
41
|
+
export const FLASH_PATCH_MAX_OUTPUT_TOKENS = DEFAULT_OUTPUT_CAP;
|
|
42
|
+
/** Output cap for Flash deep review findings. */
|
|
43
|
+
export const FLASH_REVIEW_MAX_OUTPUT_TOKENS = DEFAULT_OUTPUT_CAP;
|
|
53
44
|
// ---------------------------------------------------------------------------
|
|
54
45
|
// Temperatures
|
|
55
46
|
// ---------------------------------------------------------------------------
|
|
@@ -57,7 +57,7 @@ export declare const TOOL_CONTRACTS: readonly [{
|
|
|
57
57
|
readonly model: "gemini-3-flash-preview";
|
|
58
58
|
readonly timeoutMs: 90000;
|
|
59
59
|
readonly thinkingLevel: "minimal";
|
|
60
|
-
readonly maxOutputTokens:
|
|
60
|
+
readonly maxOutputTokens: 65536;
|
|
61
61
|
readonly temperature: 1;
|
|
62
62
|
readonly deterministicJson: true;
|
|
63
63
|
readonly params: readonly [{
|
|
@@ -82,7 +82,7 @@ export declare const TOOL_CONTRACTS: readonly [{
|
|
|
82
82
|
readonly model: "gemini-3-flash-preview";
|
|
83
83
|
readonly timeoutMs: 90000;
|
|
84
84
|
readonly thinkingLevel: "minimal";
|
|
85
|
-
readonly maxOutputTokens:
|
|
85
|
+
readonly maxOutputTokens: 65536;
|
|
86
86
|
readonly temperature: 1;
|
|
87
87
|
readonly deterministicJson: true;
|
|
88
88
|
readonly params: readonly [{
|
|
@@ -104,10 +104,10 @@ export declare const TOOL_CONTRACTS: readonly [{
|
|
|
104
104
|
}, {
|
|
105
105
|
readonly name: "inspect_code_quality";
|
|
106
106
|
readonly purpose: "Deep code review over the cached diff.";
|
|
107
|
-
readonly model: "gemini-3-
|
|
107
|
+
readonly model: "gemini-3-flash-preview";
|
|
108
108
|
readonly timeoutMs: 120000;
|
|
109
109
|
readonly thinkingLevel: "high";
|
|
110
|
-
readonly maxOutputTokens:
|
|
110
|
+
readonly maxOutputTokens: 65536;
|
|
111
111
|
readonly temperature: 1;
|
|
112
112
|
readonly deterministicJson: true;
|
|
113
113
|
readonly params: readonly [{
|
|
@@ -142,10 +142,10 @@ export declare const TOOL_CONTRACTS: readonly [{
|
|
|
142
142
|
}, {
|
|
143
143
|
readonly name: "suggest_search_replace";
|
|
144
144
|
readonly purpose: "Generate verbatim search/replace fix blocks for one finding.";
|
|
145
|
-
readonly model: "gemini-3-
|
|
145
|
+
readonly model: "gemini-3-flash-preview";
|
|
146
146
|
readonly timeoutMs: 120000;
|
|
147
147
|
readonly thinkingLevel: "high";
|
|
148
|
-
readonly maxOutputTokens:
|
|
148
|
+
readonly maxOutputTokens: 65536;
|
|
149
149
|
readonly temperature: 1;
|
|
150
150
|
readonly deterministicJson: true;
|
|
151
151
|
readonly params: readonly [{
|
|
@@ -171,7 +171,7 @@ export declare const TOOL_CONTRACTS: readonly [{
|
|
|
171
171
|
readonly model: "gemini-3-flash-preview";
|
|
172
172
|
readonly timeoutMs: 90000;
|
|
173
173
|
readonly thinkingLevel: "medium";
|
|
174
|
-
readonly maxOutputTokens:
|
|
174
|
+
readonly maxOutputTokens: 65536;
|
|
175
175
|
readonly temperature: 1;
|
|
176
176
|
readonly deterministicJson: true;
|
|
177
177
|
readonly params: readonly [{
|
|
@@ -208,7 +208,7 @@ export declare const TOOL_CONTRACTS: readonly [{
|
|
|
208
208
|
readonly model: "gemini-3-flash-preview";
|
|
209
209
|
readonly timeoutMs: 90000;
|
|
210
210
|
readonly thinkingLevel: "medium";
|
|
211
|
-
readonly maxOutputTokens:
|
|
211
|
+
readonly maxOutputTokens: 65536;
|
|
212
212
|
readonly temperature: 1;
|
|
213
213
|
readonly deterministicJson: true;
|
|
214
214
|
readonly params: readonly [{
|
|
@@ -227,7 +227,7 @@ export declare const TOOL_CONTRACTS: readonly [{
|
|
|
227
227
|
readonly model: "gemini-3-flash-preview";
|
|
228
228
|
readonly timeoutMs: 90000;
|
|
229
229
|
readonly thinkingLevel: "minimal";
|
|
230
|
-
readonly maxOutputTokens:
|
|
230
|
+
readonly maxOutputTokens: 65536;
|
|
231
231
|
readonly temperature: 1;
|
|
232
232
|
readonly deterministicJson: true;
|
|
233
233
|
readonly params: readonly [{
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ANALYSIS_TEMPERATURE, CREATIVE_TEMPERATURE,
|
|
1
|
+
import { ANALYSIS_TEMPERATURE, CREATIVE_TEMPERATURE, DEFAULT_TIMEOUT_EXTENDED_MS, FLASH_API_BREAKING_MAX_OUTPUT_TOKENS, FLASH_COMPLEXITY_MAX_OUTPUT_TOKENS, FLASH_HIGH_THINKING_LEVEL, FLASH_MODEL, FLASH_PATCH_MAX_OUTPUT_TOKENS, FLASH_REVIEW_MAX_OUTPUT_TOKENS, FLASH_TEST_PLAN_MAX_OUTPUT_TOKENS, FLASH_THINKING_LEVEL, FLASH_TRIAGE_MAX_OUTPUT_TOKENS, FLASH_TRIAGE_THINKING_LEVEL, PATCH_TEMPERATURE, TRIAGE_TEMPERATURE, } from './model-config.js';
|
|
2
2
|
const DEFAULT_TIMEOUT_FLASH_MS = 90_000;
|
|
3
3
|
export const INSPECTION_FOCUS_AREAS = [
|
|
4
4
|
'security',
|
|
@@ -119,10 +119,10 @@ export const TOOL_CONTRACTS = [
|
|
|
119
119
|
{
|
|
120
120
|
name: 'inspect_code_quality',
|
|
121
121
|
purpose: 'Deep code review over the cached diff.',
|
|
122
|
-
model:
|
|
123
|
-
timeoutMs:
|
|
124
|
-
thinkingLevel:
|
|
125
|
-
maxOutputTokens:
|
|
122
|
+
model: FLASH_MODEL,
|
|
123
|
+
timeoutMs: DEFAULT_TIMEOUT_EXTENDED_MS,
|
|
124
|
+
thinkingLevel: FLASH_HIGH_THINKING_LEVEL,
|
|
125
|
+
maxOutputTokens: FLASH_REVIEW_MAX_OUTPUT_TOKENS,
|
|
126
126
|
temperature: ANALYSIS_TEMPERATURE,
|
|
127
127
|
deterministicJson: true,
|
|
128
128
|
params: [
|
|
@@ -169,10 +169,10 @@ export const TOOL_CONTRACTS = [
|
|
|
169
169
|
{
|
|
170
170
|
name: 'suggest_search_replace',
|
|
171
171
|
purpose: 'Generate verbatim search/replace fix blocks for one finding.',
|
|
172
|
-
model:
|
|
173
|
-
timeoutMs:
|
|
174
|
-
thinkingLevel:
|
|
175
|
-
maxOutputTokens:
|
|
172
|
+
model: FLASH_MODEL,
|
|
173
|
+
timeoutMs: DEFAULT_TIMEOUT_EXTENDED_MS,
|
|
174
|
+
thinkingLevel: FLASH_HIGH_THINKING_LEVEL,
|
|
175
|
+
maxOutputTokens: FLASH_PATCH_MAX_OUTPUT_TOKENS,
|
|
176
176
|
temperature: PATCH_TEMPERATURE,
|
|
177
177
|
deterministicJson: true,
|
|
178
178
|
params: [
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { CreateTaskRequestHandlerExtra } from '@modelcontextprotocol/sdk/experimental/tasks/interfaces.js';
|
|
2
1
|
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
3
2
|
import type { ZodRawShapeCompat } from '@modelcontextprotocol/sdk/server/zod-compat.js';
|
|
4
3
|
import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
|
|
@@ -26,6 +25,11 @@ interface ProgressNotificationParams {
|
|
|
26
25
|
total?: number;
|
|
27
26
|
message?: string;
|
|
28
27
|
}
|
|
28
|
+
interface ProgressPayload {
|
|
29
|
+
current: number;
|
|
30
|
+
total?: number;
|
|
31
|
+
message?: string;
|
|
32
|
+
}
|
|
29
33
|
interface ProgressExtra {
|
|
30
34
|
_meta?: {
|
|
31
35
|
progressToken?: unknown;
|
|
@@ -66,8 +70,6 @@ export interface StructuredToolTaskConfig<TInput extends object = Record<string,
|
|
|
66
70
|
requiresDiff?: boolean;
|
|
67
71
|
/** Optional override for schema validation retries. Defaults to GEMINI_SCHEMA_RETRIES env var. */
|
|
68
72
|
schemaRetries?: number;
|
|
69
|
-
/** Optional Gemini model to use (e.g. 'gemini-3-pro-preview'). */
|
|
70
|
-
model?: string;
|
|
71
73
|
/** Optional thinking level. */
|
|
72
74
|
thinkingLevel?: 'minimal' | 'low' | 'medium' | 'high';
|
|
73
75
|
/** Optional timeout in ms for the Gemini call. Defaults to 90,000 ms. Use DEFAULT_TIMEOUT_PRO_MS for Pro model calls. */
|
|
@@ -101,29 +103,33 @@ export declare function wrapToolHandler<TInput, TResult extends CallToolResult>(
|
|
|
101
103
|
toolName: string;
|
|
102
104
|
progressContext?: (input: TInput) => string;
|
|
103
105
|
}, handler: (input: TInput, extra: ProgressExtra) => Promise<TResult> | TResult): (input: TInput, extra: ProgressExtra) => Promise<TResult>;
|
|
104
|
-
interface
|
|
105
|
-
|
|
106
|
+
interface TaskStatusReporter {
|
|
107
|
+
updateStatus: (message: string) => Promise<void>;
|
|
108
|
+
storeResult?: (status: 'completed' | 'failed', result: CallToolResult) => Promise<void>;
|
|
106
109
|
}
|
|
107
|
-
export declare class
|
|
108
|
-
private readonly server;
|
|
110
|
+
export declare class ToolExecutionRunner<TInput extends object, TResult extends object, TFinal extends TResult> {
|
|
109
111
|
private readonly config;
|
|
110
|
-
private readonly
|
|
111
|
-
private readonly task;
|
|
112
|
+
private readonly signal?;
|
|
112
113
|
private diffSlotSnapshot;
|
|
113
114
|
private hasSnapshot;
|
|
114
115
|
private responseSchema;
|
|
115
116
|
private readonly onLog;
|
|
116
117
|
private readonly reportProgress;
|
|
118
|
+
private readonly statusReporter;
|
|
117
119
|
private progressContext;
|
|
118
120
|
private lastStatusMessage;
|
|
119
|
-
constructor(
|
|
121
|
+
constructor(config: StructuredToolTaskConfig<TInput, TResult, TFinal>, dependencies: {
|
|
122
|
+
onLog: (level: string, data: unknown) => Promise<void>;
|
|
123
|
+
reportProgress: (payload: ProgressPayload) => Promise<void>;
|
|
124
|
+
statusReporter: TaskStatusReporter;
|
|
125
|
+
}, signal?: AbortSignal | undefined);
|
|
120
126
|
setResponseSchemaOverride(responseSchema: Record<string, unknown>): void;
|
|
121
127
|
setDiffSlotSnapshot(diffSlotSnapshot: DiffSlot | undefined): void;
|
|
122
128
|
private updateStatusMessage;
|
|
123
129
|
private storeResultSafely;
|
|
124
130
|
private executeValidation;
|
|
125
131
|
private executeModelCall;
|
|
126
|
-
run(input: unknown): Promise<
|
|
132
|
+
run(input: unknown): Promise<CallToolResult>;
|
|
127
133
|
}
|
|
128
134
|
export declare function registerStructuredToolTask<TInput extends object, TResult extends object = Record<string, unknown>, TFinal extends TResult = TResult>(server: McpServer, config: StructuredToolTaskConfig<TInput, TResult, TFinal>): void;
|
|
129
135
|
export {};
|
package/dist/lib/tool-factory.js
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { DefaultOutputSchema } from '../schemas/outputs.js';
|
|
3
|
-
import { createNoDiffError, getDiff } from './diff-store.js';
|
|
3
|
+
import { createNoDiffError, diffStaleWarningMs, getDiff, } from './diff-store.js';
|
|
4
4
|
import { validateDiffBudget } from './diff.js';
|
|
5
5
|
import { createCachedEnvInt } from './env-config.js';
|
|
6
6
|
import { getErrorMessage, RETRYABLE_UPSTREAM_ERROR_PATTERN } from './errors.js';
|
|
7
7
|
import { stripJsonSchemaConstraints } from './gemini-schema.js';
|
|
8
|
-
import { generateStructuredJson
|
|
8
|
+
import { generateStructuredJson } from './gemini.js';
|
|
9
9
|
import { createErrorToolResponse, createToolResponse, } from './tool-response.js';
|
|
10
|
-
const DEFAULT_TASK_TTL_MS = 30 * 60 * 1_000;
|
|
11
10
|
// Named progress step indices for 7-step progress (0–6).
|
|
12
11
|
const STEP_STARTING = 0;
|
|
13
12
|
const STEP_VALIDATING = 1;
|
|
@@ -28,7 +27,6 @@ const DEFAULT_SCHEMA_RETRY_ERROR_CHARS = 1_500;
|
|
|
28
27
|
const schemaRetryErrorCharsConfig = createCachedEnvInt('MAX_SCHEMA_RETRY_ERROR_CHARS', DEFAULT_SCHEMA_RETRY_ERROR_CHARS);
|
|
29
28
|
const DETERMINISTIC_JSON_RETRY_NOTE = 'Deterministic JSON mode: keep key names exactly as schema-defined and preserve stable field ordering.';
|
|
30
29
|
const JSON_PARSE_ERROR_PATTERN = /model produced invalid json/i;
|
|
31
|
-
const MODEL_IMMEDIATE_RESPONSE_META_KEY = 'io.modelcontextprotocol/model-immediate-response';
|
|
32
30
|
const responseSchemaCache = new WeakMap();
|
|
33
31
|
const progressReporterCache = new WeakMap();
|
|
34
32
|
function buildToolAnnotations(annotations) {
|
|
@@ -107,9 +105,6 @@ function createGenerationRequest(config, promptParts, responseSchema, onLog, sig
|
|
|
107
105
|
responseSchema,
|
|
108
106
|
onLog,
|
|
109
107
|
};
|
|
110
|
-
if (config.model !== undefined) {
|
|
111
|
-
request.model = config.model;
|
|
112
|
-
}
|
|
113
108
|
if (config.thinkingLevel !== undefined) {
|
|
114
109
|
request.thinkingLevel = config.thinkingLevel;
|
|
115
110
|
}
|
|
@@ -248,16 +243,6 @@ function normalizeProgressContext(context) {
|
|
|
248
243
|
function formatProgressStep(toolName, context, metadata) {
|
|
249
244
|
return `${toolName}: ${context} [${metadata}]`;
|
|
250
245
|
}
|
|
251
|
-
function friendlyModelName(model) {
|
|
252
|
-
if (!model)
|
|
253
|
-
return 'calling model';
|
|
254
|
-
const normalized = model.toLowerCase();
|
|
255
|
-
if (normalized.includes('pro'))
|
|
256
|
-
return 'calling Pro';
|
|
257
|
-
if (normalized.includes('flash'))
|
|
258
|
-
return 'calling Flash';
|
|
259
|
-
return 'calling model';
|
|
260
|
-
}
|
|
261
246
|
function formatProgressCompletion(toolName, context, outcome) {
|
|
262
247
|
return `🗒 ${toolName}: ${context} • ${outcome}`;
|
|
263
248
|
}
|
|
@@ -318,32 +303,6 @@ function asObjectRecord(value) {
|
|
|
318
303
|
}
|
|
319
304
|
return { payload: value };
|
|
320
305
|
}
|
|
321
|
-
function createGeminiLogger(server, taskId) {
|
|
322
|
-
return async (level, data) => {
|
|
323
|
-
try {
|
|
324
|
-
await server.sendLoggingMessage({
|
|
325
|
-
level: toLoggingLevel(level),
|
|
326
|
-
logger: 'gemini',
|
|
327
|
-
data: {
|
|
328
|
-
requestId: getCurrentRequestId(),
|
|
329
|
-
taskId,
|
|
330
|
-
...asObjectRecord(data),
|
|
331
|
-
},
|
|
332
|
-
});
|
|
333
|
-
}
|
|
334
|
-
catch {
|
|
335
|
-
try {
|
|
336
|
-
const timestamp = new Date().toISOString();
|
|
337
|
-
const payload = JSON.stringify(asObjectRecord(data));
|
|
338
|
-
console.error(`[${timestamp}] [gemini:${level}] ${taskId} - ${payload}`);
|
|
339
|
-
}
|
|
340
|
-
catch {
|
|
341
|
-
// Safe fallback if JSON stringify fails
|
|
342
|
-
console.error(`[gemini:${level}] ${taskId} - (logging failed)`);
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
};
|
|
346
|
-
}
|
|
347
306
|
export function wrapToolHandler(options, handler) {
|
|
348
307
|
return async (input, extra) => {
|
|
349
308
|
const context = normalizeProgressContext(options.progressContext?.(input));
|
|
@@ -396,26 +355,24 @@ async function validateRequest(config, inputRecord, ctx) {
|
|
|
396
355
|
}
|
|
397
356
|
return undefined;
|
|
398
357
|
}
|
|
399
|
-
export class
|
|
400
|
-
server;
|
|
358
|
+
export class ToolExecutionRunner {
|
|
401
359
|
config;
|
|
402
|
-
|
|
403
|
-
task;
|
|
360
|
+
signal;
|
|
404
361
|
diffSlotSnapshot;
|
|
405
362
|
hasSnapshot = false;
|
|
406
363
|
responseSchema;
|
|
407
364
|
onLog;
|
|
408
365
|
reportProgress;
|
|
366
|
+
statusReporter;
|
|
409
367
|
progressContext;
|
|
410
368
|
lastStatusMessage;
|
|
411
|
-
constructor(
|
|
412
|
-
this.server = server;
|
|
369
|
+
constructor(config, dependencies, signal) {
|
|
413
370
|
this.config = config;
|
|
414
|
-
this.
|
|
415
|
-
this.task = task;
|
|
371
|
+
this.signal = signal;
|
|
416
372
|
this.responseSchema = getCachedGeminiResponseSchema(config);
|
|
417
|
-
this.onLog =
|
|
418
|
-
this.reportProgress =
|
|
373
|
+
this.onLog = dependencies.onLog;
|
|
374
|
+
this.reportProgress = dependencies.reportProgress;
|
|
375
|
+
this.statusReporter = dependencies.statusReporter;
|
|
419
376
|
this.progressContext = DEFAULT_PROGRESS_CONTEXT;
|
|
420
377
|
}
|
|
421
378
|
setResponseSchemaOverride(responseSchema) {
|
|
@@ -431,7 +388,7 @@ export class ToolTaskRunner {
|
|
|
431
388
|
return;
|
|
432
389
|
}
|
|
433
390
|
try {
|
|
434
|
-
await this.
|
|
391
|
+
await this.statusReporter.updateStatus(message);
|
|
435
392
|
this.lastStatusMessage = message;
|
|
436
393
|
}
|
|
437
394
|
catch {
|
|
@@ -439,8 +396,11 @@ export class ToolTaskRunner {
|
|
|
439
396
|
}
|
|
440
397
|
}
|
|
441
398
|
async storeResultSafely(status, result) {
|
|
399
|
+
if (!this.statusReporter.storeResult) {
|
|
400
|
+
return;
|
|
401
|
+
}
|
|
442
402
|
try {
|
|
443
|
-
await this.
|
|
403
|
+
await this.statusReporter.storeResult(status, result);
|
|
444
404
|
}
|
|
445
405
|
catch (storeErr) {
|
|
446
406
|
await this.onLog('error', {
|
|
@@ -468,9 +428,9 @@ export class ToolTaskRunner {
|
|
|
468
428
|
await this.updateStatusMessage(validationMessage);
|
|
469
429
|
await reportProgressCompletionUpdate(this.reportProgress, this.config.name, this.progressContext, 'rejected');
|
|
470
430
|
await this.storeResultSafely('completed', validationError);
|
|
471
|
-
return
|
|
431
|
+
return validationError;
|
|
472
432
|
}
|
|
473
|
-
return
|
|
433
|
+
return undefined;
|
|
474
434
|
}
|
|
475
435
|
async executeModelCall(systemInstruction, prompt) {
|
|
476
436
|
let parsed;
|
|
@@ -478,7 +438,7 @@ export class ToolTaskRunner {
|
|
|
478
438
|
const maxRetries = this.config.schemaRetries ?? geminiSchemaRetriesConfig.get();
|
|
479
439
|
for (let attempt = 0; attempt <= maxRetries; attempt += 1) {
|
|
480
440
|
try {
|
|
481
|
-
const raw = await generateStructuredJson(createGenerationRequest(this.config, { systemInstruction, prompt: retryPrompt }, this.responseSchema, this.onLog, this.
|
|
441
|
+
const raw = await generateStructuredJson(createGenerationRequest(this.config, { systemInstruction, prompt: retryPrompt }, this.responseSchema, this.onLog, this.signal));
|
|
482
442
|
if (attempt === 0) {
|
|
483
443
|
await this.updateStatusMessage('validating response');
|
|
484
444
|
await reportProgressStepUpdate(this.reportProgress, this.config.name, this.progressContext, STEP_VALIDATING_RESPONSE, 'validating response');
|
|
@@ -513,8 +473,6 @@ export class ToolTaskRunner {
|
|
|
513
473
|
try {
|
|
514
474
|
const inputRecord = parseToolInput(input, this.config.fullInputSchema);
|
|
515
475
|
this.progressContext = normalizeProgressContext(this.config.progressContext?.(inputRecord));
|
|
516
|
-
// Prefer createTask snapshot; fallback preserves backward compatibility
|
|
517
|
-
// for any direct constructor callers.
|
|
518
476
|
const ctx = {
|
|
519
477
|
diffSlot: this.hasSnapshot ? this.diffSlotSnapshot : getDiff(),
|
|
520
478
|
};
|
|
@@ -522,40 +480,52 @@ export class ToolTaskRunner {
|
|
|
522
480
|
await this.updateStatusMessage('starting');
|
|
523
481
|
await reportProgressStepUpdate(this.reportProgress, this.config.name, this.progressContext, STEP_VALIDATING, 'validating input');
|
|
524
482
|
await this.updateStatusMessage('validating input');
|
|
525
|
-
|
|
526
|
-
|
|
483
|
+
const validationError = await this.executeValidation(inputRecord, ctx);
|
|
484
|
+
if (validationError) {
|
|
485
|
+
return validationError;
|
|
527
486
|
}
|
|
528
487
|
await reportProgressStepUpdate(this.reportProgress, this.config.name, this.progressContext, STEP_BUILDING_PROMPT, 'building prompt');
|
|
529
488
|
await this.updateStatusMessage('building prompt');
|
|
530
489
|
const promptParts = this.config.buildPrompt(inputRecord, ctx);
|
|
531
490
|
const { prompt, systemInstruction } = promptParts;
|
|
532
|
-
|
|
533
|
-
await
|
|
534
|
-
await this.updateStatusMessage(modelLabel);
|
|
491
|
+
await reportProgressStepUpdate(this.reportProgress, this.config.name, this.progressContext, STEP_CALLING_MODEL, 'calling model');
|
|
492
|
+
await this.updateStatusMessage('calling model');
|
|
535
493
|
const parsed = await this.executeModelCall(systemInstruction, prompt);
|
|
536
494
|
await reportProgressStepUpdate(this.reportProgress, this.config.name, this.progressContext, STEP_FINALIZING, 'finalizing');
|
|
537
495
|
await this.updateStatusMessage('finalizing');
|
|
538
496
|
const finalResult = (this.config.transformResult
|
|
539
497
|
? this.config.transformResult(inputRecord, parsed, ctx)
|
|
540
498
|
: parsed);
|
|
541
|
-
|
|
499
|
+
let textContent = this.config.formatOutput
|
|
542
500
|
? this.config.formatOutput(finalResult)
|
|
543
501
|
: undefined;
|
|
502
|
+
if (ctx.diffSlot) {
|
|
503
|
+
const ageMs = Date.now() - new Date(ctx.diffSlot.generatedAt).getTime();
|
|
504
|
+
if (ageMs > diffStaleWarningMs.get()) {
|
|
505
|
+
const ageMinutes = Math.round(ageMs / 60_000);
|
|
506
|
+
const warning = `\n\n⚠️ Warning: The analyzed diff is over ${ageMinutes} minutes old. If you have made recent changes, please run generate_diff again.`;
|
|
507
|
+
textContent = textContent ? textContent + warning : warning;
|
|
508
|
+
}
|
|
509
|
+
}
|
|
544
510
|
const outcome = this.config.formatOutcome?.(finalResult) ?? 'completed';
|
|
545
511
|
await reportProgressCompletionUpdate(this.reportProgress, this.config.name, this.progressContext, outcome);
|
|
546
512
|
await this.updateStatusMessage(`completed: ${outcome}`);
|
|
547
|
-
|
|
513
|
+
const successResponse = createToolResponse({
|
|
548
514
|
ok: true,
|
|
549
515
|
result: finalResult,
|
|
550
|
-
}, textContent)
|
|
516
|
+
}, textContent);
|
|
517
|
+
await this.storeResultSafely('completed', successResponse);
|
|
518
|
+
return successResponse;
|
|
551
519
|
}
|
|
552
520
|
catch (error) {
|
|
553
521
|
const errorMessage = getErrorMessage(error);
|
|
554
522
|
const errorMeta = classifyErrorMeta(error, errorMessage);
|
|
555
523
|
const outcome = errorMeta.kind === 'cancelled' ? 'cancelled' : 'failed';
|
|
556
524
|
await this.updateStatusMessage(createFailureStatusMessage(outcome, errorMessage));
|
|
557
|
-
|
|
525
|
+
const errorResponse = createErrorToolResponse(this.config.errorCode, errorMessage, undefined, errorMeta);
|
|
526
|
+
await this.storeResultSafely('failed', errorResponse);
|
|
558
527
|
await reportProgressCompletionUpdate(this.reportProgress, this.config.name, this.progressContext, outcome);
|
|
528
|
+
return errorResponse; // Return safe error response
|
|
559
529
|
}
|
|
560
530
|
}
|
|
561
531
|
}
|
|
@@ -564,50 +534,35 @@ export function registerStructuredToolTask(server, config) {
|
|
|
564
534
|
geminiSchema: config.geminiSchema,
|
|
565
535
|
resultSchema: config.resultSchema,
|
|
566
536
|
});
|
|
567
|
-
server.
|
|
537
|
+
server.registerTool(config.name, {
|
|
568
538
|
title: config.title,
|
|
569
539
|
description: config.description,
|
|
570
540
|
inputSchema: config.inputSchema,
|
|
571
541
|
outputSchema: DefaultOutputSchema,
|
|
572
542
|
annotations: buildToolAnnotations(config.annotations),
|
|
573
|
-
}, {
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
});
|
|
593
|
-
}
|
|
594
|
-
catch {
|
|
595
|
-
console.error(`[task-runner:${config.name}] ${getErrorMessage(error)}`);
|
|
596
|
-
}
|
|
597
|
-
});
|
|
598
|
-
});
|
|
599
|
-
return {
|
|
600
|
-
task,
|
|
601
|
-
_meta: {
|
|
602
|
-
[MODEL_IMMEDIATE_RESPONSE_META_KEY]: `${config.name} accepted as task ${task.taskId}`,
|
|
543
|
+
}, async (input, extra) => {
|
|
544
|
+
const runner = new ToolExecutionRunner(config, {
|
|
545
|
+
onLog: async (level, data) => {
|
|
546
|
+
// Standard logging for tool calls
|
|
547
|
+
try {
|
|
548
|
+
await server.sendLoggingMessage({
|
|
549
|
+
level: toLoggingLevel(level),
|
|
550
|
+
logger: 'gemini',
|
|
551
|
+
data: asObjectRecord(data),
|
|
552
|
+
});
|
|
553
|
+
}
|
|
554
|
+
catch {
|
|
555
|
+
// Fallback if logging fails
|
|
556
|
+
}
|
|
557
|
+
},
|
|
558
|
+
reportProgress: createProgressReporter(extra),
|
|
559
|
+
statusReporter: {
|
|
560
|
+
updateStatus: async () => {
|
|
561
|
+
// No-op for standard tool calls as they don't have a persistent task status
|
|
603
562
|
},
|
|
604
|
-
}
|
|
605
|
-
}
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
},
|
|
609
|
-
getTaskResult: async (_input, extra) => {
|
|
610
|
-
return (await extra.taskStore.getTaskResult(extra.taskId));
|
|
611
|
-
},
|
|
563
|
+
},
|
|
564
|
+
});
|
|
565
|
+
runner.setResponseSchemaOverride(responseSchema);
|
|
566
|
+
return await runner.run(input);
|
|
612
567
|
});
|
|
613
568
|
}
|
package/dist/resources/index.js
CHANGED
|
@@ -83,7 +83,7 @@ function registerToolInfoResources(server) {
|
|
|
83
83
|
}
|
|
84
84
|
export const DIFF_RESOURCE_DESCRIPTION = 'The most recently generated diff, cached by generate_diff. Read by all review tools automatically.';
|
|
85
85
|
function registerDiffResource(server) {
|
|
86
|
-
server.registerResource('diff-current',
|
|
86
|
+
server.registerResource('diff-current', DIFF_RESOURCE_URI, {
|
|
87
87
|
title: 'Current Diff',
|
|
88
88
|
description: DIFF_RESOURCE_DESCRIPTION,
|
|
89
89
|
mimeType: PATCH_MIME_TYPE,
|
|
@@ -22,7 +22,7 @@ ${parameterLines.join('\n')}
|
|
|
22
22
|
- **Output**: \`${contract.outputShape}\``;
|
|
23
23
|
}
|
|
24
24
|
const modelInfo = [
|
|
25
|
-
|
|
25
|
+
'Flash',
|
|
26
26
|
contract.thinkingLevel ? `Thinking:${contract.thinkingLevel}` : '',
|
|
27
27
|
`${Math.round(contract.timeoutMs / 1_000)}s`,
|
|
28
28
|
`MaxTokens:${contract.maxOutputTokens}`,
|
|
@@ -26,8 +26,8 @@ generate_review_summary ──→ overallRisk ──────┤
|
|
|
26
26
|
|
|
27
27
|
## When to Use Each Tool
|
|
28
28
|
|
|
29
|
-
- **Triage**: \`analyze_pr_impact\`, \`generate_review_summary
|
|
30
|
-
- **Inspection**: \`inspect_code_quality
|
|
29
|
+
- **Triage**: \`analyze_pr_impact\`, \`generate_review_summary\`.
|
|
30
|
+
- **Inspection**: \`inspect_code_quality\`.
|
|
31
31
|
- **Fixes**: \`suggest_search_replace\` (one finding/call).
|
|
32
32
|
- **Tests**: \`generate_test_plan\`.
|
|
33
33
|
- **Complexity**: \`analyze_time_space_complexity\`.
|
|
@@ -19,7 +19,6 @@ export function registerAnalyzeComplexityTool(server) {
|
|
|
19
19
|
fullInputSchema: AnalyzeComplexityInputSchema,
|
|
20
20
|
resultSchema: AnalyzeComplexityResultSchema,
|
|
21
21
|
errorCode: 'E_ANALYZE_COMPLEXITY',
|
|
22
|
-
model: TOOL_CONTRACT.model,
|
|
23
22
|
timeoutMs: TOOL_CONTRACT.timeoutMs,
|
|
24
23
|
maxOutputTokens: TOOL_CONTRACT.maxOutputTokens,
|
|
25
24
|
...buildStructuredToolRuntimeOptions(TOOL_CONTRACT),
|
|
@@ -22,7 +22,6 @@ export function registerAnalyzePrImpactTool(server) {
|
|
|
22
22
|
fullInputSchema: AnalyzePrImpactInputSchema,
|
|
23
23
|
resultSchema: PrImpactResultSchema,
|
|
24
24
|
errorCode: 'E_ANALYZE_IMPACT',
|
|
25
|
-
model: TOOL_CONTRACT.model,
|
|
26
25
|
timeoutMs: TOOL_CONTRACT.timeoutMs,
|
|
27
26
|
maxOutputTokens: TOOL_CONTRACT.maxOutputTokens,
|
|
28
27
|
...buildStructuredToolRuntimeOptions(TOOL_CONTRACT),
|
|
@@ -19,7 +19,6 @@ export function registerDetectApiBreakingTool(server) {
|
|
|
19
19
|
fullInputSchema: DetectApiBreakingInputSchema,
|
|
20
20
|
resultSchema: DetectApiBreakingResultSchema,
|
|
21
21
|
errorCode: 'E_DETECT_API_BREAKING',
|
|
22
|
-
model: TOOL_CONTRACT.model,
|
|
23
22
|
timeoutMs: TOOL_CONTRACT.timeoutMs,
|
|
24
23
|
maxOutputTokens: TOOL_CONTRACT.maxOutputTokens,
|
|
25
24
|
...buildStructuredToolRuntimeOptions(TOOL_CONTRACT),
|
|
@@ -36,7 +36,6 @@ export function registerGenerateReviewSummaryTool(server) {
|
|
|
36
36
|
fullInputSchema: GenerateReviewSummaryInputSchema,
|
|
37
37
|
resultSchema: ReviewSummaryModelSchema,
|
|
38
38
|
errorCode: 'E_REVIEW_SUMMARY',
|
|
39
|
-
model: TOOL_CONTRACT.model,
|
|
40
39
|
timeoutMs: TOOL_CONTRACT.timeoutMs,
|
|
41
40
|
maxOutputTokens: TOOL_CONTRACT.maxOutputTokens,
|
|
42
41
|
...buildStructuredToolRuntimeOptions(TOOL_CONTRACT),
|
|
@@ -23,7 +23,6 @@ export function registerGenerateTestPlanTool(server) {
|
|
|
23
23
|
fullInputSchema: GenerateTestPlanInputSchema,
|
|
24
24
|
resultSchema: TestPlanResultSchema,
|
|
25
25
|
errorCode: 'E_GENERATE_TEST_PLAN',
|
|
26
|
-
model: TOOL_CONTRACT.model,
|
|
27
26
|
timeoutMs: TOOL_CONTRACT.timeoutMs,
|
|
28
27
|
maxOutputTokens: TOOL_CONTRACT.maxOutputTokens,
|
|
29
28
|
...buildStructuredToolRuntimeOptions(TOOL_CONTRACT),
|
|
@@ -28,7 +28,6 @@ export function registerInspectCodeQualityTool(server) {
|
|
|
28
28
|
resultSchema: CodeQualityOutputSchema,
|
|
29
29
|
geminiSchema: CodeQualityResultSchema,
|
|
30
30
|
errorCode: 'E_INSPECT_QUALITY',
|
|
31
|
-
model: TOOL_CONTRACT.model,
|
|
32
31
|
timeoutMs: TOOL_CONTRACT.timeoutMs,
|
|
33
32
|
maxOutputTokens: TOOL_CONTRACT.maxOutputTokens,
|
|
34
33
|
...buildStructuredToolRuntimeOptions(TOOL_CONTRACT),
|
|
@@ -23,7 +23,6 @@ export function registerSuggestSearchReplaceTool(server) {
|
|
|
23
23
|
fullInputSchema: SuggestSearchReplaceInputSchema,
|
|
24
24
|
resultSchema: SearchReplaceResultSchema,
|
|
25
25
|
errorCode: 'E_SUGGEST_SEARCH_REPLACE',
|
|
26
|
-
model: TOOL_CONTRACT.model,
|
|
27
26
|
timeoutMs: TOOL_CONTRACT.timeoutMs,
|
|
28
27
|
maxOutputTokens: TOOL_CONTRACT.maxOutputTokens,
|
|
29
28
|
...buildStructuredToolRuntimeOptions(TOOL_CONTRACT),
|