tachibot-mcp 2.17.0 → 2.19.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 +59 -0
- package/dist/src/modes/auditor.js +2 -1
- package/dist/src/modes/challenger.js +6 -5
- package/dist/src/server.js +15 -16
- package/dist/src/tools/advanced-modes.js +31 -6
- package/dist/src/tools/gemini-tools.js +31 -10
- package/dist/src/tools/grok-enhanced.js +6 -3
- package/dist/src/tools/grok-tools.js +28 -7
- package/dist/src/tools/openai-tools.js +22 -5
- package/dist/src/tools/openrouter-tools.js +195 -60
- package/dist/src/tools/perplexity-tools.js +11 -2
- package/dist/src/tools/planner-tools.js +355 -87
- package/dist/src/utils/ansi-renderer.js +33 -14
- package/dist/src/utils/ansi-styles.js +21 -10
- package/dist/src/utils/file-reader.js +96 -0
- package/dist/src/utils/format-constants.js +47 -9
- package/docs/superpowers/plans/2026-03-21-files-param-all-tools.md +364 -0
- package/docs/superpowers/plans/2026-03-21-files-param-and-website-bump.md +504 -0
- package/docs/superpowers/plans/2026-03-21-goal-oriented-checkpoints.md +584 -0
- package/docs/superpowers/plans/2026-03-21-kimi-decompose-readability.md +365 -0
- package/docs/superpowers/plans/2026-03-21-sparse-mode-ansi-bold-headers.md +252 -0
- package/docs/superpowers/plans/2026-03-21-sparse-mode-fixes.md +187 -0
- package/package.json +1 -1
- package/skills/blueprint/SKILL.md +55 -8
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,65 @@ All notable changes to TachiBot MCP will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [2.19.0] - 2026-03-21
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- **Sparse render mode** (`RENDER_OUTPUT=sparse`) — lightweight output formatting with ~72 tokens overhead per response
|
|
12
|
+
- **ANSI model badges** — colored background badges for model name (provider color) + tool name (charcoal bg)
|
|
13
|
+
- **Pastel section headers** — emoji section headers (`🧠 HEADER ───`) rendered as teal bg + dark bold text badges
|
|
14
|
+
- **Color-coded verdicts** — `✅ pass` (sage green), `🫠 partial` (soft yellow), `💀 fail` (rose) with colored bg badges
|
|
15
|
+
- **Summary badge** — tool name displayed as bold charcoal badge next to model badge
|
|
16
|
+
- **`stripMarkdown` options** — `{ boldHeaders: true }` converts markdown/emoji headers to ANSI-styled badges
|
|
17
|
+
- **Empty input guard** on `stripMarkdown` — early return for empty/whitespace input
|
|
18
|
+
- **Strip markdown headers** — `##` prefixes and `───` decorators removed from output
|
|
19
|
+
- **8 unit tests** for `stripMarkdown` covering headers, bold, bullets, code blocks, HR, empty input
|
|
20
|
+
|
|
21
|
+
### Fixed
|
|
22
|
+
- **ANSI truncation corruption** — truncate raw content BEFORE applying ANSI badges (prevents mid-escape code corruption)
|
|
23
|
+
- **Summary badge without model** — tools returning null from `inferModelFromTool` (think, focus) still show tool name badge
|
|
24
|
+
- **Unused imports** — cleaned up 10+ unused imports/variables in server.ts
|
|
25
|
+
|
|
26
|
+
### Changed
|
|
27
|
+
- **Emoji palette** — analysis 🧠, insight 🔮, key 🗝, verdict 👩⚖️ (replaced 🔍🧿🪩🎯)
|
|
28
|
+
- **Auditor/Challenger** — use `EMOJI_PALETTE` constants instead of hardcoded emoji
|
|
29
|
+
- **Planner** — topological task ordering with T-ID preservation and Dependencies metadata
|
|
30
|
+
|
|
31
|
+
## [2.18.0] - 2026-03-21
|
|
32
|
+
|
|
33
|
+
### Added
|
|
34
|
+
- **Goal-oriented checkpoints** — `planner_maker` and `planner_runner` now accept `goal` parameter for success criteria tracking
|
|
35
|
+
- **6 checkpoint gates** with 5 different models (no adjacent repeats): step1 (Gemini Sherlock), 10% (Grok), 25% (GPT + amendment protocol), 50% (Qwen), 80% (Kimi decompose), 100% (GPT+Gemini dual judge)
|
|
36
|
+
- **Reflexion Lite** — at 100%, Gemini reflects on what worked/failed, lesson saved to devlog
|
|
37
|
+
- **Amendment protocol** — at 25%, structured plan revision (evidence + proposed changes + impact) with human gate
|
|
38
|
+
- **Unblinded checkpoints** — `diff`, `testResults`, `modifiedFiles` params replace blind `code.substring(0,1500)` with real evidence
|
|
39
|
+
- **`files` param on all analysis tools** — 39 tools across 9 files can now read ACTUAL CODE from disk via `readFilesIntoContext()`
|
|
40
|
+
- **Shared `src/utils/file-reader.ts`** — reusable file reader with line range support (`file.ts:100-200`), size limits, directory expansion
|
|
41
|
+
- **Blueprint skill updated** — `goal` param, prompt template, `planner_runner` as default execution path
|
|
42
|
+
|
|
43
|
+
### Fixed
|
|
44
|
+
- **Step index reset bug** — filtered arrays used local index instead of original step number (found by 3-model consensus: Kimi + Gemini + Qwen reading actual code)
|
|
45
|
+
- **Truncation indicators** — `code.substring()` now adds `[truncated]` so judge models know they're seeing partial code
|
|
46
|
+
|
|
47
|
+
## [2.17.2] - 2026-03-21
|
|
48
|
+
|
|
49
|
+
### Added
|
|
50
|
+
- **`files` parameter on 13+ more tools** — grok_architect, grok_brainstorm, grok_reason_v4, openai_explain, kimi_code, kimi_long_context, gemini_judge, gemini_brainstorm, gemini_query, gemini_summarize, qwq_reason, qwen_competitive, qwen_general (38 tools now support `files`)
|
|
51
|
+
- **Directory expansion in file reader** — pass `src/tools/` to read all code files in a directory (non-recursive, capped at 20 files)
|
|
52
|
+
- **Smart char budget** — multi-file reads distribute token budget across files to prevent context overflow
|
|
53
|
+
|
|
54
|
+
## [2.17.1] - 2026-03-21
|
|
55
|
+
|
|
56
|
+
### Fixed
|
|
57
|
+
- **kimi_decompose readability overhaul** — output now uses OVERVIEW/STRUCTURE/DETAILS/RISKS sections instead of dense inline metadata
|
|
58
|
+
- **Reasoning leak stripped** — Kimi K2.5 dumps CoT into content; now extracted via `<output>` tags with OVERVIEW fallback
|
|
59
|
+
- **Conflicting FORMAT_INSTRUCTION removed** — emoji headers and verdict lines no longer clash with decomposition formatting
|
|
60
|
+
- **Heartbeat interval fixed** — was incorrectly set to 240s instead of default 5s; network timeout now correctly passed to callOpenRouter (360s)
|
|
61
|
+
- **Type safety** — args typed from zod schema, unused `log` removed, `||` replaced with `??`
|
|
62
|
+
|
|
63
|
+
### Changed
|
|
64
|
+
- **Smart decomposition** — model now infers context, constraints, risks, and measurable criteria even when user doesn't state them
|
|
65
|
+
- **Tuned for format adherence** — temperature 0.3 (was 0.5), maxTokens 4500 (was 6000), timeout 360s (was 180s default)
|
|
66
|
+
|
|
8
67
|
## [2.17.0] - 2026-03-21
|
|
9
68
|
|
|
10
69
|
### Changed
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { EMOJI_PALETTE } from '../utils/format-constants.js';
|
|
1
2
|
export class Auditor {
|
|
2
3
|
constructor() {
|
|
3
4
|
this.defaultModel = 'perplexity-sonar-pro';
|
|
@@ -328,7 +329,7 @@ export class Auditor {
|
|
|
328
329
|
// Critical assumptions
|
|
329
330
|
const criticalAssumptions = assumptions.filter(a => a.risk === 'high');
|
|
330
331
|
if (criticalAssumptions.length > 0) {
|
|
331
|
-
synthesis += `**Critical Assumptions**
|
|
332
|
+
synthesis += `**Critical Assumptions** ${EMOJI_PALETTE.bad}:\n`;
|
|
332
333
|
criticalAssumptions.forEach(assumption => {
|
|
333
334
|
synthesis += `- ${assumption.description}\n`;
|
|
334
335
|
synthesis += ` Validation: ${assumption.validationMethod}\n`;
|
|
@@ -20,6 +20,7 @@ import { getChallengerModels } from '../config/model-defaults.js';
|
|
|
20
20
|
import { createProgressStream } from '../utils/progress-stream.js';
|
|
21
21
|
import { smartAPIClient } from '../utils/smart-api-client.js';
|
|
22
22
|
import { getSmartTimeout } from '../config/timeout-config.js';
|
|
23
|
+
import { EMOJI_PALETTE } from '../utils/format-constants.js';
|
|
23
24
|
import { execSync } from 'child_process';
|
|
24
25
|
// import {
|
|
25
26
|
// renderTable,
|
|
@@ -755,7 +756,7 @@ Write concrete, specific analysis. Do NOT include brackets or placeholders.`;
|
|
|
755
756
|
lines.push('');
|
|
756
757
|
const challengesTableData = challenges.map((ch, i) => {
|
|
757
758
|
const claim = claims.find(c => c.id === ch.claimId);
|
|
758
|
-
const severityIcon = ch.severity === 'high' ?
|
|
759
|
+
const severityIcon = ch.severity === 'high' ? EMOJI_PALETTE.bad : ch.severity === 'medium' ? EMOJI_PALETTE.warn : EMOJI_PALETTE.good;
|
|
759
760
|
return {
|
|
760
761
|
'#': String(i + 1),
|
|
761
762
|
Severity: `${severityIcon} ${ch.severity}`,
|
|
@@ -768,7 +769,7 @@ Write concrete, specific analysis. Do NOT include brackets or placeholders.`;
|
|
|
768
769
|
// Show full challenges below
|
|
769
770
|
challenges.forEach((ch, i) => {
|
|
770
771
|
const claim = claims.find(c => c.id === ch.claimId);
|
|
771
|
-
const severityIcon = ch.severity === 'high' ?
|
|
772
|
+
const severityIcon = ch.severity === 'high' ? EMOJI_PALETTE.bad : ch.severity === 'medium' ? EMOJI_PALETTE.warn : EMOJI_PALETTE.good;
|
|
772
773
|
lines.push(`${severityIcon} **Challenge #${i + 1}** (${ch.severity} severity)`);
|
|
773
774
|
lines.push(`Original: "${claim?.text}"`);
|
|
774
775
|
lines.push('');
|
|
@@ -863,9 +864,9 @@ Write concrete, specific analysis. Do NOT include brackets or placeholders.`;
|
|
|
863
864
|
lines.push('');
|
|
864
865
|
lines.push(renderKeyValueTable({
|
|
865
866
|
'Total Challenges': String(challenges.length),
|
|
866
|
-
'
|
|
867
|
-
'
|
|
868
|
-
'
|
|
867
|
+
[EMOJI_PALETTE.bad + ' High Severity']: String(highSeverity),
|
|
868
|
+
[EMOJI_PALETTE.warn + ' Medium Severity']: String(mediumSeverity),
|
|
869
|
+
[EMOJI_PALETTE.good + ' Low Severity']: String(lowSeverity),
|
|
869
870
|
'Alternatives': String(alternatives.length),
|
|
870
871
|
'Groupthink Risk': groupthinkRisk,
|
|
871
872
|
}));
|
package/dist/src/server.js
CHANGED
|
@@ -25,7 +25,7 @@ const savedThemeVars = {
|
|
|
25
25
|
RENDER_OUTPUT: process.env.RENDER_OUTPUT,
|
|
26
26
|
TACHIBOT_THEME: process.env.TACHIBOT_THEME,
|
|
27
27
|
};
|
|
28
|
-
|
|
28
|
+
dotenvConfig({
|
|
29
29
|
path: envPath,
|
|
30
30
|
override: true // API keys from .env take priority
|
|
31
31
|
});
|
|
@@ -52,7 +52,7 @@ import { z } from "zod";
|
|
|
52
52
|
import { InstructionOrchestrator } from "./orchestrator-instructions.js";
|
|
53
53
|
import { validateToolInput, sanitizeForLogging } from "./utils/input-validator.js";
|
|
54
54
|
import { isToolEnabled, logToolConfiguration } from "./utils/tool-config.js";
|
|
55
|
-
import {
|
|
55
|
+
import { renderOutput } from "./utils/ansi-renderer.js";
|
|
56
56
|
import { getToolAnnotations } from "./utils/tool-annotations.js";
|
|
57
57
|
import { truncateSmart } from "./utils/stream-distill.js";
|
|
58
58
|
import { trackToolCall, inferModelFromTool, estimateTokens, isTrackingEnabled, getUsageSummary, getAllReposSummary, getStatsJson, resetStats } from "./utils/usage-tracker.js";
|
|
@@ -158,16 +158,17 @@ function safeAddTool(tool) {
|
|
|
158
158
|
// Silently ignore tracking errors
|
|
159
159
|
}
|
|
160
160
|
}
|
|
161
|
-
//
|
|
162
|
-
// doesn't render markdown in tool results (shows raw ** and ### as text)
|
|
161
|
+
// Apply render mode (sparse = badge + bold headers + stripped, etc.)
|
|
163
162
|
if (typeof result === 'string') {
|
|
164
|
-
|
|
165
|
-
//
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
163
|
+
const model = inferModelFromTool(tool.name) || undefined;
|
|
164
|
+
// Truncate raw content BEFORE ANSI rendering — prevents mid-escape corruption
|
|
165
|
+
let raw = result;
|
|
166
|
+
const MAX_RAW_CHARS = 24000;
|
|
167
|
+
if (raw.length > MAX_RAW_CHARS) {
|
|
168
|
+
raw = truncateSmart(raw, MAX_RAW_CHARS);
|
|
169
169
|
}
|
|
170
|
-
|
|
170
|
+
const rendered = renderOutput(raw, { model, summary: tool.name });
|
|
171
|
+
return { type: "text", text: rendered };
|
|
171
172
|
}
|
|
172
173
|
return result;
|
|
173
174
|
}
|
|
@@ -226,7 +227,7 @@ safeAddTool({
|
|
|
226
227
|
}),
|
|
227
228
|
execute: async (args, mcpContext) => {
|
|
228
229
|
const { log } = mcpContext;
|
|
229
|
-
let { query, mode = "simple", context, domain, tokenEfficient = false, rounds = 5, executeNow = true, models, temperature = 0.7, saveSession = true, maxTokensPerRound = 2000, pingPongStyle = "collaborative" } = args;
|
|
230
|
+
let { query, mode = "simple", context, domain, tokenEfficient = false, rounds = 5, executeNow: _executeNow = true, models, temperature = 0.7, saveSession: _saveSession = true, maxTokensPerRound: _maxTokensPerRound = 2000, pingPongStyle: _pingPongStyle = "collaborative" } = args;
|
|
230
231
|
// Validate and sanitize input
|
|
231
232
|
const queryValidation = validateToolInput(query);
|
|
232
233
|
if (!queryValidation.valid) {
|
|
@@ -332,8 +333,7 @@ TIPS FOR EFFECTIVE SYNTHESIS:
|
|
|
332
333
|
Ready to help synthesize your collective intelligence results!`;
|
|
333
334
|
default: // simple mode
|
|
334
335
|
// BigText header disabled - plain text only
|
|
335
|
-
|
|
336
|
-
const focusBadge = '';
|
|
336
|
+
// BigText header/badge removed — plain text only
|
|
337
337
|
return `Enhanced reasoning for: "${query}"
|
|
338
338
|
${context ? `Context: ${context}` : ''}
|
|
339
339
|
|
|
@@ -458,8 +458,7 @@ MemoryProvider: Pluggable memory (devlog, mem0, custom). Set TACHIBOT_MEMORY_PRO
|
|
|
458
458
|
});
|
|
459
459
|
// Build response with model output if available
|
|
460
460
|
// BigText header disabled - plain text only
|
|
461
|
-
|
|
462
|
-
const thinkHeader = '';
|
|
461
|
+
// BigText header/badge removed — plain text only
|
|
463
462
|
let response = '';
|
|
464
463
|
if (result.modelResponse) {
|
|
465
464
|
response += `## Model Response (${args.model}):\n\n${result.modelResponse}\n\n---\n\n`;
|
|
@@ -691,7 +690,7 @@ async function initializeServer() {
|
|
|
691
690
|
console.error("✅ Server.start() called successfully");
|
|
692
691
|
// Keep the process alive with a heartbeat
|
|
693
692
|
// This ensures the server doesn't exit prematurely
|
|
694
|
-
|
|
693
|
+
setInterval(() => {
|
|
695
694
|
// Heartbeat to keep process alive
|
|
696
695
|
// Log every 30 seconds to show we're still alive
|
|
697
696
|
const now = new Date().toISOString();
|
|
@@ -5,6 +5,7 @@ import { Architect } from "../modes/architect.js";
|
|
|
5
5
|
import { CodeReviewer } from "../modes/code-reviewer.js";
|
|
6
6
|
import { DocumentationWriter } from "../modes/documentation-writer.js";
|
|
7
7
|
import { TestArchitect } from "../modes/test-architect.js";
|
|
8
|
+
import { readFilesIntoContext } from "../utils/file-reader.js";
|
|
8
9
|
// Workflow tools removed - using workflow-runner.ts instead
|
|
9
10
|
const auditor = new Auditor();
|
|
10
11
|
const commitGuardian = new CommitGuardian();
|
|
@@ -18,11 +19,15 @@ export const auditorTool = {
|
|
|
18
19
|
description: "Evidence-based audit. Put the CONTEXT in the 'context' parameter.",
|
|
19
20
|
parameters: z.object({
|
|
20
21
|
context: z.string().describe("What to audit (REQUIRED - put your audit request here)"),
|
|
22
|
+
files: z.array(z.string()).optional().describe("File paths to read as code context. Supports line ranges: 'src/foo.ts:100-200'. Model sees ACTUAL CODE."),
|
|
21
23
|
evidenceRequired: z.boolean().optional().describe("Require evidence for claims")
|
|
22
24
|
}),
|
|
23
25
|
execute: async (args, { log }) => {
|
|
24
26
|
log.info("Starting audit");
|
|
25
|
-
const
|
|
27
|
+
const fileContext = args.files?.length
|
|
28
|
+
? `\n\nSOURCE CODE:\n${readFilesIntoContext(args.files)}`
|
|
29
|
+
: "";
|
|
30
|
+
const result = await auditor.audit(args.context + fileContext, {
|
|
26
31
|
evidenceRequired: args.evidenceRequired
|
|
27
32
|
});
|
|
28
33
|
log.info("Audit complete", {
|
|
@@ -38,6 +43,7 @@ export const commitGuardianTool = {
|
|
|
38
43
|
description: "Pre-commit validation. Put the CONTEXT in the 'context' parameter.",
|
|
39
44
|
parameters: z.object({
|
|
40
45
|
context: z.string().describe("Code changes to validate (REQUIRED - put your diff/changes here)"),
|
|
46
|
+
files: z.array(z.string()).optional().describe("File paths to read as code context. Supports line ranges: 'src/foo.ts:100-200'. Model sees ACTUAL CODE."),
|
|
41
47
|
strict: z.boolean().optional().describe("Use strict validation rules"),
|
|
42
48
|
checkSecurity: z.boolean().optional().describe("Check for security issues"),
|
|
43
49
|
checkQuality: z.boolean().optional().describe("Check code quality"),
|
|
@@ -45,7 +51,10 @@ export const commitGuardianTool = {
|
|
|
45
51
|
}),
|
|
46
52
|
execute: async (args, { log }) => {
|
|
47
53
|
log.info("Validating commit");
|
|
48
|
-
const
|
|
54
|
+
const fileContext = args.files?.length
|
|
55
|
+
? `\n\nSOURCE CODE:\n${readFilesIntoContext(args.files)}`
|
|
56
|
+
: "";
|
|
57
|
+
const result = await commitGuardian.validate(args.context + fileContext, {
|
|
49
58
|
strict: args.strict,
|
|
50
59
|
checkSecurity: args.checkSecurity,
|
|
51
60
|
checkQuality: args.checkQuality,
|
|
@@ -66,6 +75,7 @@ export const architectTool = {
|
|
|
66
75
|
parameters: z.object({
|
|
67
76
|
query: z.string().describe("What to analyze in the codebase (REQUIRED - put your question here)"),
|
|
68
77
|
path: z.string().optional().describe("Path to the codebase to analyze"),
|
|
78
|
+
files: z.array(z.string()).optional().describe("File paths to read as code context. Supports line ranges: 'src/foo.ts:100-200'. Model sees ACTUAL CODE."),
|
|
69
79
|
depth: z.enum(["shallow", "normal", "deep"])
|
|
70
80
|
.optional()
|
|
71
81
|
.describe("Analysis depth - must be one of: shallow, normal, deep"),
|
|
@@ -76,7 +86,10 @@ export const architectTool = {
|
|
|
76
86
|
depth: args.depth || "normal",
|
|
77
87
|
path: args.path
|
|
78
88
|
});
|
|
79
|
-
const
|
|
89
|
+
const fileContext = args.files?.length
|
|
90
|
+
? `\n\nSOURCE CODE:\n${readFilesIntoContext(args.files)}`
|
|
91
|
+
: "";
|
|
92
|
+
const result = await architect.analyze(args.query + fileContext, {
|
|
80
93
|
path: args.path,
|
|
81
94
|
depth: args.depth,
|
|
82
95
|
focusAreas: args.focusAreas
|
|
@@ -98,6 +111,7 @@ export const codeReviewerTool = {
|
|
|
98
111
|
parameters: z.object({
|
|
99
112
|
code: z.string().describe("The actual source code to review (REQUIRED - put your code here)"),
|
|
100
113
|
language: z.string().optional().describe("Programming language (e.g., 'typescript', 'python')"),
|
|
114
|
+
files: z.array(z.string()).optional().describe("File paths to read as code context. Supports line ranges: 'src/foo.ts:100-200'. Model sees ACTUAL CODE."),
|
|
101
115
|
focusAreas: z.array(z.enum(['security', 'performance', 'readability', 'bugs', 'best-practices']))
|
|
102
116
|
.optional()
|
|
103
117
|
.describe("Focus areas - array of: security, performance, readability, bugs, best-practices"),
|
|
@@ -111,7 +125,10 @@ export const codeReviewerTool = {
|
|
|
111
125
|
language: args.language || 'auto-detect',
|
|
112
126
|
focusAreas: args.focusAreas || 'all'
|
|
113
127
|
});
|
|
114
|
-
const
|
|
128
|
+
const fileContext = args.files?.length
|
|
129
|
+
? `\n\nSOURCE CODE:\n${readFilesIntoContext(args.files)}`
|
|
130
|
+
: "";
|
|
131
|
+
const result = await codeReviewer.review(args.code + fileContext, {
|
|
115
132
|
language: args.language,
|
|
116
133
|
focusAreas: args.focusAreas,
|
|
117
134
|
severity: args.severity,
|
|
@@ -131,6 +148,7 @@ export const documentationWriterTool = {
|
|
|
131
148
|
description: "Documentation generation. Put the CODE in the 'code' parameter.",
|
|
132
149
|
parameters: z.object({
|
|
133
150
|
code: z.string().describe("The source code to document (REQUIRED - put your code here)"),
|
|
151
|
+
files: z.array(z.string()).optional().describe("File paths to read as code context. Supports line ranges: 'src/foo.ts:100-200'. Model sees ACTUAL CODE."),
|
|
134
152
|
style: z.enum(['narrative', 'technical', 'beginner-friendly', 'api-reference'])
|
|
135
153
|
.optional()
|
|
136
154
|
.describe("Documentation style - must be one of: narrative, technical, beginner-friendly, api-reference"),
|
|
@@ -145,7 +163,10 @@ export const documentationWriterTool = {
|
|
|
145
163
|
style: args.style || 'narrative',
|
|
146
164
|
format: args.format || 'markdown'
|
|
147
165
|
});
|
|
148
|
-
const
|
|
166
|
+
const fileContext = args.files?.length
|
|
167
|
+
? `\n\nSOURCE CODE:\n${readFilesIntoContext(args.files)}`
|
|
168
|
+
: "";
|
|
169
|
+
const result = await documentationWriter.generateDocs(args.code + fileContext, {
|
|
149
170
|
style: args.style,
|
|
150
171
|
includeExamples: args.includeExamples,
|
|
151
172
|
generateToc: args.generateToc,
|
|
@@ -166,6 +187,7 @@ export const testArchitectTool = {
|
|
|
166
187
|
description: "Test suite design. Put the CODE in the 'code' parameter.",
|
|
167
188
|
parameters: z.object({
|
|
168
189
|
code: z.string().describe("The source code to create tests for (REQUIRED - put your code here)"),
|
|
190
|
+
files: z.array(z.string()).optional().describe("File paths to read as code context. Supports line ranges: 'src/foo.ts:100-200'. Model sees ACTUAL CODE."),
|
|
169
191
|
testFramework: z.enum(['jest', 'mocha', 'vitest', 'cypress', 'playwright'])
|
|
170
192
|
.optional()
|
|
171
193
|
.describe("Test framework - must be one of: jest, mocha, vitest, cypress, playwright"),
|
|
@@ -183,7 +205,10 @@ export const testArchitectTool = {
|
|
|
183
205
|
testTypes: args.testTypes || ['unit', 'integration', 'e2e'],
|
|
184
206
|
coverage: args.coverage || 'thorough'
|
|
185
207
|
});
|
|
186
|
-
const
|
|
208
|
+
const fileContext = args.files?.length
|
|
209
|
+
? `\n\nSOURCE CODE:\n${readFilesIntoContext(args.files)}`
|
|
210
|
+
: "";
|
|
211
|
+
const result = await testArchitect.architectTests(args.code + fileContext, {
|
|
187
212
|
testFramework: args.testFramework,
|
|
188
213
|
testTypes: args.testTypes,
|
|
189
214
|
coverage: args.coverage,
|
|
@@ -11,6 +11,7 @@ import { stripFormatting } from "../utils/format-stripper.js";
|
|
|
11
11
|
import { FORMAT_INSTRUCTION } from "../utils/format-constants.js";
|
|
12
12
|
import { withHeartbeat } from "../utils/streaming-helper.js";
|
|
13
13
|
import { getTimeoutConfig } from "../config/timeout-config.js";
|
|
14
|
+
import { readFilesIntoContext } from "../utils/file-reader.js";
|
|
14
15
|
// Note: renderOutput is applied centrally in server.ts safeAddTool() - no need to import here
|
|
15
16
|
// NOTE: dotenv is loaded in server.ts before any imports
|
|
16
17
|
// No need to reload here - just read from process.env
|
|
@@ -171,7 +172,8 @@ export const geminiQueryTool = {
|
|
|
171
172
|
model: z.enum(["gemini-3", "pro", "flash"])
|
|
172
173
|
.optional()
|
|
173
174
|
.default("gemini-3")
|
|
174
|
-
.describe("Model variant - must be one of: gemini-3 (default), pro, flash")
|
|
175
|
+
.describe("Model variant - must be one of: gemini-3 (default), pro, flash"),
|
|
176
|
+
files: z.array(z.string()).optional().describe("File paths to read as code context. Supports line ranges: 'src/foo.ts:100-200'. Model sees ACTUAL CODE.")
|
|
175
177
|
}),
|
|
176
178
|
execute: async (args, { log, reportProgress }) => {
|
|
177
179
|
let model = GEMINI_MODELS.GEMINI_3_PRO; // Default to Gemini 3
|
|
@@ -182,8 +184,9 @@ export const geminiQueryTool = {
|
|
|
182
184
|
model = GEMINI_MODELS.PRO;
|
|
183
185
|
}
|
|
184
186
|
// Skip validation - queries may contain code or LLM-generated content
|
|
187
|
+
const fileContext = args.files?.length ? `\n\nSOURCE CODE:\n${readFilesIntoContext(args.files)}` : "";
|
|
185
188
|
const reportFn = reportProgress ?? (async () => { });
|
|
186
|
-
const result = await withHeartbeat(() => callGemini(args.prompt, model, undefined, 0.7, 'llm-orchestration'), reportFn);
|
|
189
|
+
const result = await withHeartbeat(() => callGemini(args.prompt + fileContext, model, undefined, 0.7, 'llm-orchestration'), reportFn);
|
|
187
190
|
return stripFormatting(result);
|
|
188
191
|
}
|
|
189
192
|
};
|
|
@@ -200,7 +203,8 @@ export const geminiBrainstormTool = {
|
|
|
200
203
|
parameters: z.object({
|
|
201
204
|
prompt: z.string().describe("The ideas or topic to organize and refine (REQUIRED - put raw ideas or topic here)"),
|
|
202
205
|
claudeThoughts: z.string().optional().describe("Claude's initial thoughts or raw ideas to cluster and refine"),
|
|
203
|
-
maxClusters: z.number().optional().default(5).describe("Number of idea clusters to create (default: 5)")
|
|
206
|
+
maxClusters: z.number().optional().default(5).describe("Number of idea clusters to create (default: 5)"),
|
|
207
|
+
files: z.array(z.string()).optional().describe("File paths to read as code context. Supports line ranges: 'src/foo.ts:100-200'. Model sees ACTUAL CODE.")
|
|
204
208
|
}),
|
|
205
209
|
execute: async (args, { log, reportProgress }) => {
|
|
206
210
|
const systemPrompt = `Convergent synthesis engine. Output consumed by automated toolchain.
|
|
@@ -226,8 +230,11 @@ Per cluster: Name | Score (1-10) | Top ideas (ranked) | Key insight
|
|
|
226
230
|
Final: Which cluster has highest expected value and why. State the meta-pattern.
|
|
227
231
|
No preamble. Structured output only.
|
|
228
232
|
${FORMAT_INSTRUCTION}`;
|
|
233
|
+
const fileContext = args.files?.length
|
|
234
|
+
? `\n\nSOURCE CODE:\n${readFilesIntoContext(args.files)}`
|
|
235
|
+
: "";
|
|
229
236
|
const reportFn = reportProgress ?? (async () => { });
|
|
230
|
-
const response = await withHeartbeat(() => callGemini(args.prompt, GEMINI_MODELS.GEMINI_3_PRO, systemPrompt, 0.7, 'llm-orchestration'), reportFn);
|
|
237
|
+
const response = await withHeartbeat(() => callGemini(args.prompt + fileContext, GEMINI_MODELS.GEMINI_3_PRO, systemPrompt, 0.7, 'llm-orchestration'), reportFn);
|
|
231
238
|
return stripFormatting(response);
|
|
232
239
|
}
|
|
233
240
|
};
|
|
@@ -241,6 +248,7 @@ export const geminiAnalyzeCodeTool = {
|
|
|
241
248
|
parameters: z.object({
|
|
242
249
|
code: z.string().describe("The actual source code to analyze (REQUIRED - put your code here)"),
|
|
243
250
|
language: z.string().optional().describe("Programming language (e.g., 'typescript', 'python')"),
|
|
251
|
+
files: z.array(z.string()).optional().describe("File paths to read as code context. Supports line ranges: 'src/foo.ts:100-200'. Model sees ACTUAL CODE."),
|
|
244
252
|
focus: z.string().optional().default("general").describe("Analysis focus (e.g., quality, security, performance, bugs, general)")
|
|
245
253
|
}),
|
|
246
254
|
execute: async (args, { log, reportProgress }) => {
|
|
@@ -255,9 +263,12 @@ export const geminiAnalyzeCodeTool = {
|
|
|
255
263
|
const systemPrompt = `Expert code reviewer. ${args.language || ''} code.
|
|
256
264
|
${focusText}.
|
|
257
265
|
${FORMAT_INSTRUCTION}`;
|
|
266
|
+
const fileContext = args.files?.length
|
|
267
|
+
? `\n\nSOURCE CODE:\n${readFilesIntoContext(args.files)}`
|
|
268
|
+
: "";
|
|
258
269
|
// Skip validation - code analysis naturally contains patterns that trigger false positives
|
|
259
270
|
const reportFn = reportProgress ?? (async () => { });
|
|
260
|
-
const result = await withHeartbeat(() => callGemini(`Analyze this code:\n\n\`\`\`${args.language || ''}\n${args.code}\n
|
|
271
|
+
const result = await withHeartbeat(() => callGemini(`Analyze this code:\n\n\`\`\`${args.language || ''}\n${args.code}\n\`\`\`${fileContext}`, GEMINI_MODELS.GEMINI_3_PRO, systemPrompt, 0.3, 'llm-orchestration'), reportFn);
|
|
261
272
|
return stripFormatting(result);
|
|
262
273
|
}
|
|
263
274
|
};
|
|
@@ -270,6 +281,7 @@ export const geminiAnalyzeTextTool = {
|
|
|
270
281
|
description: "Rhetorical analysis: dissect arguments for bias, logical fallacies, and persuasion tactics. Use for evaluating claims, detecting manipulation, or understanding argument structure. Put the TEXT in the 'text' parameter.",
|
|
271
282
|
parameters: z.object({
|
|
272
283
|
text: z.string().describe("The text to analyze (REQUIRED - put your text here)"),
|
|
284
|
+
files: z.array(z.string()).optional().describe("File paths to read as code context. Supports line ranges: 'src/foo.ts:100-200'. Model sees ACTUAL CODE."),
|
|
273
285
|
type: z.string()
|
|
274
286
|
.optional()
|
|
275
287
|
.default("rhetoric")
|
|
@@ -306,8 +318,11 @@ OUTPUT:
|
|
|
306
318
|
${analysisText}
|
|
307
319
|
No preamble. Structured output only.
|
|
308
320
|
${FORMAT_INSTRUCTION}`;
|
|
321
|
+
const fileContext = args.files?.length
|
|
322
|
+
? `\n\nSOURCE CODE:\n${readFilesIntoContext(args.files)}`
|
|
323
|
+
: "";
|
|
309
324
|
const reportFn = reportProgress ?? (async () => { });
|
|
310
|
-
const result = await withHeartbeat(() => callGemini(`Analyze this text:\n\n${args.text}`, GEMINI_MODELS.GEMINI_3_PRO, systemPrompt, 0.3, 'llm-orchestration'), reportFn);
|
|
325
|
+
const result = await withHeartbeat(() => callGemini(`Analyze this text:\n\n${args.text}${fileContext}`, GEMINI_MODELS.GEMINI_3_PRO, systemPrompt, 0.3, 'llm-orchestration'), reportFn);
|
|
311
326
|
return stripFormatting(result);
|
|
312
327
|
}
|
|
313
328
|
};
|
|
@@ -327,7 +342,8 @@ export const geminiSummarizeTool = {
|
|
|
327
342
|
format: z.enum(["paragraph", "bullet-points", "outline"])
|
|
328
343
|
.optional()
|
|
329
344
|
.default("paragraph")
|
|
330
|
-
.describe("Output format - must be one of: paragraph, bullet-points, outline")
|
|
345
|
+
.describe("Output format - must be one of: paragraph, bullet-points, outline"),
|
|
346
|
+
files: z.array(z.string()).optional().describe("File paths to read as code context. Supports line ranges: 'src/foo.ts:100-200'. Model sees ACTUAL CODE.")
|
|
331
347
|
}),
|
|
332
348
|
execute: async (args, { log, reportProgress }) => {
|
|
333
349
|
const lengthGuides = {
|
|
@@ -349,8 +365,9 @@ Focus on:
|
|
|
349
365
|
- Conclusions and implications
|
|
350
366
|
${FORMAT_INSTRUCTION}`;
|
|
351
367
|
// Skip validation for internal summarization calls
|
|
368
|
+
const fileContext = args.files?.length ? `\n\nSOURCE CODE:\n${readFilesIntoContext(args.files)}` : "";
|
|
352
369
|
const reportFn = reportProgress ?? (async () => { });
|
|
353
|
-
const result = await withHeartbeat(() => callGemini(`Summarize this content:\n\n${args.content}
|
|
370
|
+
const result = await withHeartbeat(() => callGemini(`Summarize this content:\n\n${args.content}` + fileContext, GEMINI_MODELS.GEMINI_3_PRO, systemPrompt, 0.3, 'llm-orchestration'), reportFn);
|
|
354
371
|
return stripFormatting(result);
|
|
355
372
|
}
|
|
356
373
|
};
|
|
@@ -411,7 +428,8 @@ export const geminiJudgeTool = {
|
|
|
411
428
|
mode: z.enum(["synthesize", "evaluate", "rank", "resolve"])
|
|
412
429
|
.optional()
|
|
413
430
|
.default("synthesize")
|
|
414
|
-
.describe("Judge mode: synthesize (merge best), evaluate (score each), rank (order by quality), resolve (settle conflicts)")
|
|
431
|
+
.describe("Judge mode: synthesize (merge best), evaluate (score each), rank (order by quality), resolve (settle conflicts)"),
|
|
432
|
+
files: z.array(z.string()).optional().describe("File paths to read as code context. Supports line ranges: 'src/foo.ts:100-200'. Model sees ACTUAL CODE.")
|
|
415
433
|
}),
|
|
416
434
|
execute: async (args, { log, reportProgress }) => {
|
|
417
435
|
// Resolve perspectives from fallback params (AI clients sometimes use wrong param name)
|
|
@@ -475,8 +493,11 @@ ${FORMAT_INSTRUCTION}`;
|
|
|
475
493
|
const userPrompt = args.question
|
|
476
494
|
? `QUESTION: ${args.question}\n\nPERSPECTIVES TO JUDGE:\n${args.perspectives}`
|
|
477
495
|
: args.perspectives;
|
|
496
|
+
const fileContext = args.files?.length
|
|
497
|
+
? `\n\nSOURCE CODE:\n${readFilesIntoContext(args.files)}`
|
|
498
|
+
: "";
|
|
478
499
|
const reportFn = reportProgress ?? (async () => { });
|
|
479
|
-
const result = await withHeartbeat(() => callGemini(userPrompt, GEMINI_MODELS.GEMINI_3_PRO, systemPrompt, 0.3, 'llm-orchestration'), reportFn);
|
|
500
|
+
const result = await withHeartbeat(() => callGemini(userPrompt + fileContext, GEMINI_MODELS.GEMINI_3_PRO, systemPrompt, 0.3, 'llm-orchestration'), reportFn);
|
|
480
501
|
return stripFormatting(result);
|
|
481
502
|
}
|
|
482
503
|
};
|
|
@@ -7,6 +7,7 @@ import { config } from "dotenv";
|
|
|
7
7
|
import * as path from 'path';
|
|
8
8
|
import { fileURLToPath } from 'url';
|
|
9
9
|
import { getGrokApiKey, hasGrokApiKey } from "../utils/api-keys.js";
|
|
10
|
+
import { readFilesIntoContext } from "../utils/file-reader.js";
|
|
10
11
|
import { link } from "../utils/ansi-renderer.js";
|
|
11
12
|
import { stripFormatting } from "../utils/format-stripper.js";
|
|
12
13
|
import { FORMAT_INSTRUCTION } from "../utils/format-constants.js";
|
|
@@ -222,10 +223,11 @@ export const grokReasonEnhanced = {
|
|
|
222
223
|
context: z.string().optional(),
|
|
223
224
|
useHeavy: z.boolean().optional(),
|
|
224
225
|
enableLiveSearch: z.boolean().optional(),
|
|
225
|
-
maxSteps: z.number().optional()
|
|
226
|
+
maxSteps: z.number().optional(),
|
|
227
|
+
files: z.array(z.string()).optional().describe("File paths to read as code context. Supports line ranges: 'src/foo.ts:100-200'. Model sees ACTUAL CODE.")
|
|
226
228
|
}),
|
|
227
229
|
execute: async (args, { log }) => {
|
|
228
|
-
const { problem, approach = "first-principles", context, useHeavy = false, enableLiveSearch = false, maxSteps = 5 } = args;
|
|
230
|
+
const { problem, approach = "first-principles", context, useHeavy = false, enableLiveSearch = false, maxSteps = 5, files } = args;
|
|
229
231
|
const approachPrompts = {
|
|
230
232
|
analytical: "Break down the problem systematically and analyze each component",
|
|
231
233
|
creative: "Think outside the box and consider unconventional solutions",
|
|
@@ -233,6 +235,7 @@ export const grokReasonEnhanced = {
|
|
|
233
235
|
"first-principles": "Break down to fundamental truths and build up from there",
|
|
234
236
|
"multi-agent": "Consider multiple perspectives and synthesize them"
|
|
235
237
|
};
|
|
238
|
+
const fileContext = files?.length ? `\n\nSOURCE CODE:\n${readFilesIntoContext(files)}` : "";
|
|
236
239
|
const messages = [
|
|
237
240
|
{
|
|
238
241
|
role: "system",
|
|
@@ -245,7 +248,7 @@ ${FORMAT_INSTRUCTION}`
|
|
|
245
248
|
},
|
|
246
249
|
{
|
|
247
250
|
role: "user",
|
|
248
|
-
content: problem
|
|
251
|
+
content: problem + fileContext
|
|
249
252
|
}
|
|
250
253
|
];
|
|
251
254
|
const modelName = useHeavy ? 'Grok-4-Heavy' : 'Grok-4.1';
|
|
@@ -13,6 +13,7 @@ import { stripFormatting } from "../utils/format-stripper.js";
|
|
|
13
13
|
import { FORMAT_INSTRUCTION } from "../utils/format-constants.js";
|
|
14
14
|
import { tryOpenRouterGateway, isGatewayEnabled } from "../utils/openrouter-gateway.js";
|
|
15
15
|
import { withHeartbeat } from "../utils/streaming-helper.js";
|
|
16
|
+
import { readFilesIntoContext } from "../utils/file-reader.js";
|
|
16
17
|
// Note: renderOutput is applied centrally in server.ts safeAddTool() - no need to import here
|
|
17
18
|
const __filename = fileURLToPath(import.meta.url);
|
|
18
19
|
const __dirname = path.dirname(__filename);
|
|
@@ -130,6 +131,7 @@ export const grokReasonTool = {
|
|
|
130
131
|
.optional()
|
|
131
132
|
.describe("Reasoning approach (e.g., analytical, creative, systematic, first-principles)"),
|
|
132
133
|
context: z.string().optional().describe("Additional context for the problem"),
|
|
134
|
+
files: z.array(z.string()).optional().describe("File paths to read as code context. Supports line ranges: 'src/foo.ts:100-200'. Model sees ACTUAL CODE."),
|
|
133
135
|
useHeavy: z.boolean().optional().describe("Use expensive Grok 4 Heavy model ($3/$15) for complex tasks")
|
|
134
136
|
}),
|
|
135
137
|
execute: async (args, { log, reportProgress }) => {
|
|
@@ -140,6 +142,9 @@ export const grokReasonTool = {
|
|
|
140
142
|
systematic: "Follow a step-by-step logical process",
|
|
141
143
|
"first-principles": "Break down to fundamental truths and build up from there"
|
|
142
144
|
};
|
|
145
|
+
const fileContext = args.files?.length
|
|
146
|
+
? `\n\nSOURCE CODE:\n${readFilesIntoContext(args.files)}`
|
|
147
|
+
: "";
|
|
143
148
|
const messages = [
|
|
144
149
|
{
|
|
145
150
|
role: "system",
|
|
@@ -150,7 +155,7 @@ ${FORMAT_INSTRUCTION}`
|
|
|
150
155
|
},
|
|
151
156
|
{
|
|
152
157
|
role: "user",
|
|
153
|
-
content: problem
|
|
158
|
+
content: problem + fileContext
|
|
154
159
|
}
|
|
155
160
|
];
|
|
156
161
|
// Use GROK_4_1_FAST_REASONING by default (latest with enhanced reasoning!), GROK_4_HEAVY only if explicitly requested
|
|
@@ -175,6 +180,7 @@ export const grokCodeTool = {
|
|
|
175
180
|
.describe("Code task (e.g., analyze, optimize, debug, review, refactor)"),
|
|
176
181
|
code: z.string().describe("The actual source code to analyze (REQUIRED - put your code here)"),
|
|
177
182
|
language: z.string().optional().describe("Programming language (e.g., 'typescript', 'python')"),
|
|
183
|
+
files: z.array(z.string()).optional().describe("File paths to read as code context. Supports line ranges: 'src/foo.ts:100-200'. Model sees ACTUAL CODE."),
|
|
178
184
|
requirements: z.string().optional().describe("Specific requirements or focus areas")
|
|
179
185
|
}),
|
|
180
186
|
execute: async (args, { log, reportProgress }) => {
|
|
@@ -186,6 +192,9 @@ export const grokCodeTool = {
|
|
|
186
192
|
review: "Review this code for best practices and improvements",
|
|
187
193
|
refactor: "Refactor this code for better maintainability and clarity"
|
|
188
194
|
};
|
|
195
|
+
const fileContext = args.files?.length
|
|
196
|
+
? `\n\nSOURCE CODE:\n${readFilesIntoContext(args.files)}`
|
|
197
|
+
: "";
|
|
189
198
|
const messages = [
|
|
190
199
|
{
|
|
191
200
|
role: "system",
|
|
@@ -197,7 +206,7 @@ ${FORMAT_INSTRUCTION}`
|
|
|
197
206
|
},
|
|
198
207
|
{
|
|
199
208
|
role: "user",
|
|
200
|
-
content: `Code:\n\`\`\`${language || ''}\n${code}\n\`\`\``
|
|
209
|
+
content: `Code:\n\`\`\`${language || ''}\n${code}\n\`\`\`` + fileContext
|
|
201
210
|
}
|
|
202
211
|
];
|
|
203
212
|
log?.info(`Using Grok 4.1 Fast Non-Reasoning (2M context, tool-calling optimized, $0.20/$0.50)`);
|
|
@@ -218,6 +227,7 @@ export const grokDebugTool = {
|
|
|
218
227
|
issue: z.string().describe("Description of the issue or bug (REQUIRED - put your problem here)"),
|
|
219
228
|
code: z.string().optional().describe("Relevant code that has the issue"),
|
|
220
229
|
error: z.string().optional().describe("Error message or stack trace"),
|
|
230
|
+
files: z.array(z.string()).optional().describe("File paths to read as code context. Supports line ranges: 'src/foo.ts:100-200'. Model sees ACTUAL CODE."),
|
|
221
231
|
context: z.string().optional().describe("Additional context about the environment or conditions")
|
|
222
232
|
}),
|
|
223
233
|
execute: async (args, { log, reportProgress }) => {
|
|
@@ -232,6 +242,9 @@ export const grokDebugTool = {
|
|
|
232
242
|
if (context) {
|
|
233
243
|
prompt += `\nContext: ${context}\n`;
|
|
234
244
|
}
|
|
245
|
+
const fileContext = args.files?.length
|
|
246
|
+
? `\n\nSOURCE CODE:\n${readFilesIntoContext(args.files)}`
|
|
247
|
+
: "";
|
|
235
248
|
const messages = [
|
|
236
249
|
{
|
|
237
250
|
role: "system",
|
|
@@ -245,7 +258,7 @@ ${FORMAT_INSTRUCTION}`
|
|
|
245
258
|
},
|
|
246
259
|
{
|
|
247
260
|
role: "user",
|
|
248
|
-
content: prompt
|
|
261
|
+
content: prompt + fileContext
|
|
249
262
|
}
|
|
250
263
|
];
|
|
251
264
|
log?.info(`Using Grok 4.1 Fast Non-Reasoning for debugging (tool-calling optimized, $0.20/$0.50)`);
|
|
@@ -267,10 +280,14 @@ export const grokArchitectTool = {
|
|
|
267
280
|
constraints: z.string().optional().describe("Technical or business constraints to consider"),
|
|
268
281
|
scale: z.string()
|
|
269
282
|
.optional()
|
|
270
|
-
.describe("Expected scale (e.g., small, medium, large, enterprise)")
|
|
283
|
+
.describe("Expected scale (e.g., small, medium, large, enterprise)"),
|
|
284
|
+
files: z.array(z.string()).optional().describe("File paths to read as code context. Supports line ranges: 'src/foo.ts:100-200'. Model sees ACTUAL CODE."),
|
|
271
285
|
}),
|
|
272
286
|
execute: async (args, { log, reportProgress }) => {
|
|
273
287
|
const { requirements, constraints, scale } = args;
|
|
288
|
+
const fileContext = args.files?.length
|
|
289
|
+
? `\n\nSOURCE CODE:\n${readFilesIntoContext(args.files)}`
|
|
290
|
+
: "";
|
|
274
291
|
const messages = [
|
|
275
292
|
{
|
|
276
293
|
role: "system",
|
|
@@ -282,7 +299,7 @@ ${FORMAT_INSTRUCTION}`
|
|
|
282
299
|
},
|
|
283
300
|
{
|
|
284
301
|
role: "user",
|
|
285
|
-
content: requirements
|
|
302
|
+
content: requirements + fileContext
|
|
286
303
|
}
|
|
287
304
|
];
|
|
288
305
|
log?.info(`Using Grok 4.1 Fast Reasoning for architecture (latest model, $0.20/$0.50)`);
|
|
@@ -303,10 +320,14 @@ export const grokBrainstormTool = {
|
|
|
303
320
|
topic: z.string().describe("The topic to brainstorm about (REQUIRED - put your idea/topic here)"),
|
|
304
321
|
constraints: z.string().optional().describe("Any constraints or requirements to consider"),
|
|
305
322
|
numIdeas: z.number().optional().describe("Number of radical rebuilds to generate (default: 5)"),
|
|
306
|
-
forceHeavy: z.boolean().optional().describe("Use expensive Grok 4 Heavy model ($3/$15) for deeper creativity")
|
|
323
|
+
forceHeavy: z.boolean().optional().describe("Use expensive Grok 4 Heavy model ($3/$15) for deeper creativity"),
|
|
324
|
+
files: z.array(z.string()).optional().describe("File paths to read as code context. Supports line ranges: 'src/foo.ts:100-200'. Model sees ACTUAL CODE."),
|
|
307
325
|
}),
|
|
308
326
|
execute: async (args, { log, reportProgress }) => {
|
|
309
327
|
const { topic, constraints, numIdeas = 5, forceHeavy = false } = args;
|
|
328
|
+
const fileContext = args.files?.length
|
|
329
|
+
? `\n\nSOURCE CODE:\n${readFilesIntoContext(args.files)}`
|
|
330
|
+
: "";
|
|
310
331
|
const messages = [
|
|
311
332
|
{
|
|
312
333
|
role: "system",
|
|
@@ -332,7 +353,7 @@ ${FORMAT_INSTRUCTION}`
|
|
|
332
353
|
},
|
|
333
354
|
{
|
|
334
355
|
role: "user",
|
|
335
|
-
content: topic
|
|
356
|
+
content: topic + fileContext
|
|
336
357
|
}
|
|
337
358
|
];
|
|
338
359
|
const model = forceHeavy ? GrokModel.GROK_4_HEAVY : GrokModel.GROK_4_1_FAST_REASONING;
|