gaunt-sloth-assistant 0.4.2 → 0.5.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/README.md CHANGED
@@ -31,7 +31,8 @@ While there are many powerful AI assistants available, Gaunt Sloth Assistant sta
31
31
  3. **Command-line integration** - Seamless workflow integration with existing developer tools and processes
32
32
  4. **Specialized focus** - Purpose-built for code review and PR analysis rather than general-purpose assistance
33
33
  5. **Extensibility** - GSloth is based on LangChain JS and can be easily extended, configured or augmented in different ways.
34
- 6. **Cost Effectiveness** - When agentic tools will send a number of requests to figure out a user's intent burning thousands of tokens, gsloth simply sends your diff prefixed with guidelines for review.
34
+ 6. **Model Context Protocol (MCP)** - Support for MCP allows for enhanced context management.
35
+ 7. **Cost Effectiveness** - When agentic tools will send a number of requests to figure out a user's intent burning thousands of tokens, gsloth simply sends your diff prefixed with guidelines for review.
35
36
 
36
37
  Unlike proprietary solutions that restrict you to a single AI provider, Gaunt Sloth empowers developers with choice and control while maintaining the specialized capabilities needed for effective code review.
37
38
 
@@ -0,0 +1,10 @@
1
+ # v0.5.0 Add MCP support
2
+
3
+ ## New Features
4
+
5
+ ### Model Context Protocol (MCP) Support
6
+ - Added support for Model Context Protocol (MCP) for enhanced context management
7
+ - Included `@modelcontextprotocol/server-filesystem` as a dependency
8
+ - Added configuration options for MCP servers in `.gsloth.config.json`
9
+
10
+ Use at your own risk. Not super-well-tested yet.
package/dist/config.d.ts CHANGED
@@ -1,10 +1,12 @@
1
1
  import type { BaseChatModel } from '@langchain/core/language_models/chat_models';
2
+ import type { Connection } from '@langchain/mcp-adapters';
2
3
  export interface SlothConfig extends BaseSlothConfig {
3
4
  llm: BaseChatModel;
4
5
  contentProvider: string;
5
6
  requirementsProvider: string;
6
7
  projectGuidelines: string;
7
8
  projectReviewInstructions: string;
9
+ streamOutput: boolean;
8
10
  commands: {
9
11
  pr: {
10
12
  contentProvider: string;
@@ -31,6 +33,7 @@ interface BaseSlothConfig {
31
33
  requirementsProvider?: string;
32
34
  projectGuidelines?: string;
33
35
  projectReviewInstructions?: string;
36
+ streamOutput?: boolean;
34
37
  commands?: {
35
38
  pr: {
36
39
  contentProvider: string;
@@ -43,6 +46,7 @@ interface BaseSlothConfig {
43
46
  };
44
47
  requirementsProviderConfig?: Record<string, unknown>;
45
48
  contentProviderConfig?: Record<string, unknown>;
49
+ mcpServers?: Record<string, Connection>;
46
50
  }
47
51
  /**
48
52
  * @deprecated
@@ -50,11 +54,6 @@ interface BaseSlothConfig {
50
54
  */
51
55
  export interface SlothContext {
52
56
  config: SlothConfig;
53
- session: {
54
- configurable: {
55
- thread_id: string;
56
- };
57
- };
58
57
  }
59
58
  export interface LLMConfig extends Record<string, unknown> {
60
59
  type: string;
package/dist/config.js CHANGED
@@ -1,9 +1,8 @@
1
- import { v4 as uuidv4 } from 'uuid';
2
1
  import { displayDebug, displayError, displayInfo, displayWarning } from '#src/consoleUtils.js';
3
2
  import { importExternalFile, writeFileIfNotExistsWithMessages } from '#src/utils.js';
4
3
  import { existsSync, readFileSync } from 'node:fs';
5
4
  import { error, exit } from '#src/systemUtils.js';
6
- import { getGslothConfigWritePath, getGslothConfigReadPath } from '#src/filePathUtils.js';
5
+ import { getGslothConfigReadPath, getGslothConfigWritePath } from '#src/filePathUtils.js';
7
6
  export const USER_PROJECT_CONFIG_JS = '.gsloth.config.js';
8
7
  export const USER_PROJECT_CONFIG_JSON = '.gsloth.config.json';
9
8
  export const USER_PROJECT_CONFIG_MJS = '.gsloth.config.mjs';
@@ -17,6 +16,7 @@ export const DEFAULT_CONFIG = {
17
16
  requirementsProvider: 'file',
18
17
  projectGuidelines: PROJECT_GUIDELINES,
19
18
  projectReviewInstructions: PROJECT_REVIEW_INSTRUCTIONS,
19
+ streamOutput: true,
20
20
  commands: {
21
21
  pr: {
22
22
  contentProvider: 'github', // gh pr diff NN
@@ -31,7 +31,6 @@ export const DEFAULT_CONFIG = {
31
31
  */
32
32
  export const slothContext = {
33
33
  config: DEFAULT_CONFIG,
34
- session: { configurable: { thread_id: uuidv4() } },
35
34
  };
36
35
  export async function initConfig() {
37
36
  const jsonConfigPath = getGslothConfigReadPath(USER_PROJECT_CONFIG_JSON);
@@ -40,6 +39,7 @@ export async function initConfig() {
40
39
  // Try loading JSON config file first
41
40
  if (existsSync(jsonConfigPath)) {
42
41
  try {
42
+ // TODO makes sense to employ ZOD to validate config
43
43
  const jsonConfig = JSON.parse(readFileSync(jsonConfigPath, 'utf8'));
44
44
  // If the config has an LLM with a type, create the appropriate LLM instance
45
45
  if (jsonConfig.llm && typeof jsonConfig.llm === 'object' && 'type' in jsonConfig.llm) {
@@ -203,6 +203,5 @@ export function reset() {
203
203
  delete slothContext[key];
204
204
  });
205
205
  slothContext.config = DEFAULT_CONFIG;
206
- slothContext.session = { configurable: { thread_id: uuidv4() } };
207
206
  }
208
207
  //# sourceMappingURL=config.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
1
  import { BaseChatModel } from '@langchain/core/language_models/chat_models';
2
- import { BaseLanguageModelCallOptions } from '@langchain/core/language_models/base';
3
- export declare function invoke(llm: BaseChatModel, options: Partial<BaseLanguageModelCallOptions>, systemMessage: string, prompt: string): Promise<string>;
2
+ import { SlothConfig } from '#src/config.js';
3
+ export declare function invoke(llm: BaseChatModel, systemMessage: string, prompt: string, config: SlothConfig): Promise<string>;
4
4
  export declare function setVerbose(debug: boolean): void;
package/dist/llmUtils.js CHANGED
@@ -1,39 +1,76 @@
1
- import { HumanMessage, SystemMessage } from '@langchain/core/messages';
2
- import { END, MemorySaver, MessagesAnnotation, START, StateGraph } from '@langchain/langgraph';
1
+ import { HumanMessage, isAIMessageChunk, SystemMessage } from '@langchain/core/messages';
2
+ import { MultiServerMCPClient } from '@langchain/mcp-adapters';
3
+ import { display, displayError, displayInfo } from '#src/consoleUtils.js';
4
+ import { createReactAgent } from '@langchain/langgraph/prebuilt';
5
+ import { stdout } from '#src/systemUtils.js';
3
6
  const llmGlobalSettings = {
4
7
  verbose: false,
5
8
  };
6
- export async function invoke(llm, options, systemMessage, prompt) {
9
+ export async function invoke(llm, systemMessage, prompt, config) {
7
10
  if (llmGlobalSettings.verbose) {
8
11
  llm.verbose = true;
9
12
  }
10
- // This node receives the current state (messages) and invokes the LLM
11
- const callModel = async (state) => {
12
- // state.messages will contain the list including the system systemMessage and user diff
13
- const response = await llm.invoke(state.messages);
14
- // MessagesAnnotation expects the node to return the new message(s) to be added to the state.
15
- // Wrap the response in an array if it's a single message object.
16
- return { messages: response };
17
- };
18
- // Define the graph structure with MessagesAnnotation state
19
- const workflow = new StateGraph(MessagesAnnotation)
20
- // Define the node and edge
21
- .addNode('model', callModel)
22
- .addEdge(START, 'model') // Start at the 'model' node
23
- .addEdge('model', END); // End after the 'model' node completes
24
- // Set up memory (optional but good practice for potential future multi-turn interactions)
25
- const memory = new MemorySaver();
26
- // Compile the workflow into a runnable app
27
- const app = workflow.compile({ checkpointer: memory });
28
- // Construct the initial the messages including the systemMessage as a system message
29
- const messages = [new SystemMessage(systemMessage), new HumanMessage(prompt)];
30
- const output = await app.invoke({ messages }, options);
31
- const lastMessage = output.messages[output.messages.length - 1];
32
- return typeof lastMessage.content === 'string'
33
- ? lastMessage.content
34
- : JSON.stringify(lastMessage.content);
13
+ const client = getClient(config);
14
+ const tools = (await client?.getTools()) ?? [];
15
+ if (tools && tools.length > 0) {
16
+ displayInfo(`Loaded ${tools.length} MCP tools.`);
17
+ }
18
+ // Create the React agent
19
+ const agent = createReactAgent({
20
+ llm,
21
+ tools,
22
+ });
23
+ // Run the agent
24
+ try {
25
+ const messages = [new SystemMessage(systemMessage), new HumanMessage(prompt)];
26
+ display(`Connecting to LLM...`);
27
+ const stream = await agent.stream({ messages }, { streamMode: 'messages' });
28
+ const output = { aiMessage: '' };
29
+ for await (const [chunk, _metadata] of stream) {
30
+ if (isAIMessageChunk(chunk)) {
31
+ if (config.streamOutput) {
32
+ stdout.write(chunk.content, 'utf-8');
33
+ }
34
+ output.aiMessage += chunk.content;
35
+ let toolCalls = chunk.tool_calls;
36
+ if (toolCalls && toolCalls.length > 0) {
37
+ const suffix = toolCalls.length > 1 ? 's' : '';
38
+ const toolCallsString = toolCalls.map((t) => t?.name).join(', ');
39
+ displayInfo(`Using tool${suffix} ${toolCallsString}`);
40
+ }
41
+ }
42
+ }
43
+ return output.aiMessage;
44
+ }
45
+ catch (error) {
46
+ if (error instanceof Error) {
47
+ if (error?.name === 'ToolException') {
48
+ displayError(`Tool execution failed: ${error.message}`);
49
+ }
50
+ }
51
+ throw error;
52
+ }
53
+ finally {
54
+ if (client) {
55
+ console.log('closing');
56
+ await client.close();
57
+ }
58
+ }
35
59
  }
36
60
  export function setVerbose(debug) {
37
61
  llmGlobalSettings.verbose = debug;
38
62
  }
63
+ function getClient(config) {
64
+ if (config.mcpServers && Object.keys(config.mcpServers).length > 0) {
65
+ return new MultiServerMCPClient({
66
+ throwOnLoadError: true,
67
+ prefixToolNameWithServerName: true,
68
+ additionalToolNamePrefix: 'mcp',
69
+ mcpServers: config.mcpServers,
70
+ });
71
+ }
72
+ else {
73
+ return null;
74
+ }
75
+ }
39
76
  //# sourceMappingURL=llmUtils.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"llmUtils.js","sourceRoot":"","sources":["../src/llmUtils.ts"],"names":[],"mappings":"AACA,OAAO,EAAkB,YAAY,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAEvF,OAAO,EAAE,GAAG,EAAE,WAAW,EAAE,kBAAkB,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAG/F,MAAM,iBAAiB,GAAG;IACxB,OAAO,EAAE,KAAK;CACf,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,MAAM,CAC1B,GAAkB,EAClB,OAA8C,EAC9C,aAAqB,EACrB,MAAc;IAEd,IAAI,iBAAiB,CAAC,OAAO,EAAE,CAAC;QAC9B,GAAG,CAAC,OAAO,GAAG,IAAI,CAAC;IACrB,CAAC;IACD,sEAAsE;IACtE,MAAM,SAAS,GAAG,KAAK,EAAE,KAAY,EAAyC,EAAE;QAC9E,wFAAwF;QACxF,MAAM,QAAQ,GAAG,MAAO,GAAqB,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QACrE,6FAA6F;QAC7F,iEAAiE;QACjE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC;IAChC,CAAC,CAAC;IAEF,2DAA2D;IAC3D,MAAM,QAAQ,GAAG,IAAI,UAAU,CAAC,kBAAkB,CAAC;QACjD,2BAA2B;SAC1B,OAAO,CAAC,OAAO,EAAE,SAAS,CAAC;SAC3B,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC,4BAA4B;SACpD,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC,uCAAuC;IAEjE,0FAA0F;IAC1F,MAAM,MAAM,GAAG,IAAI,WAAW,EAAE,CAAC;IAEjC,2CAA2C;IAC3C,MAAM,GAAG,GAAG,QAAQ,CAAC,OAAO,CAAC,EAAE,YAAY,EAAE,MAAM,EAAE,CAAC,CAAC;IAEvD,qFAAqF;IACrF,MAAM,QAAQ,GAAc,CAAC,IAAI,aAAa,CAAC,aAAa,CAAC,EAAE,IAAI,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC;IAEzF,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,EAAE,OAAO,CAAC,CAAC;IACvD,MAAM,WAAW,GAAG,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAChE,OAAO,OAAO,WAAW,CAAC,OAAO,KAAK,QAAQ;QAC5C,CAAC,CAAC,WAAW,CAAC,OAAO;QACrB,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;AAC1C,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,KAAc;IACvC,iBAAiB,CAAC,OAAO,GAAG,KAAK,CAAC;AACpC,CAAC"}
1
+ {"version":3,"file":"llmUtils.js","sourceRoot":"","sources":["../src/llmUtils.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAGzF,OAAO,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAC/D,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC1E,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAE7C,MAAM,iBAAiB,GAAG;IACxB,OAAO,EAAE,KAAK;CACf,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,MAAM,CAC1B,GAAkB,EAClB,aAAqB,EACrB,MAAc,EACd,MAAmB;IAEnB,IAAI,iBAAiB,CAAC,OAAO,EAAE,CAAC;QAC9B,GAAG,CAAC,OAAO,GAAG,IAAI,CAAC;IACrB,CAAC;IAED,MAAM,MAAM,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC;IAEjC,MAAM,KAAK,GAAG,CAAC,MAAM,MAAM,EAAE,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC;IAC/C,IAAI,KAAK,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC9B,WAAW,CAAC,UAAU,KAAK,CAAC,MAAM,aAAa,CAAC,CAAC;IACnD,CAAC;IAED,yBAAyB;IACzB,MAAM,KAAK,GAAG,gBAAgB,CAAC;QAC7B,GAAG;QACH,KAAK;KACN,CAAC,CAAC;IAEH,gBAAgB;IAChB,IAAI,CAAC;QACH,MAAM,QAAQ,GAAc,CAAC,IAAI,aAAa,CAAC,aAAa,CAAC,EAAE,IAAI,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC;QACzF,OAAO,CAAC,sBAAsB,CAAC,CAAC;QAChC,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,UAAU,EAAE,UAAU,EAAE,CAAC,CAAC;QAE5E,MAAM,MAAM,GAAG,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC;QACjC,IAAI,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,SAAS,CAAC,IAAI,MAAM,EAAE,CAAC;YAC9C,IAAI,gBAAgB,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC5B,IAAI,MAAM,CAAC,YAAY,EAAE,CAAC;oBACxB,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,OAAiB,EAAE,OAAO,CAAC,CAAC;gBACjD,CAAC;gBACD,MAAM,CAAC,SAAS,IAAI,KAAK,CAAC,OAAO,CAAC;gBAClC,IAAI,SAAS,GAAG,KAAK,CAAC,UAAU,CAAC;gBACjC,IAAI,SAAS,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBACtC,MAAM,MAAM,GAAG,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;oBAC/C,MAAM,eAAe,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;oBACjE,WAAW,CAAC,aAAa,MAAM,IAAI,eAAe,EAAE,CAAC,CAAC;gBACxD,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO,MAAM,CAAC,SAAS,CAAC;IAC1B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;YAC3B,IAAI,KAAK,EAAE,IAAI,KAAK,eAAe,EAAE,CAAC;gBACpC,YAAY,CAAC,0BAA0B,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;YAC1D,CAAC;QACH,CAAC;QACD,MAAM,KAAK,CAAC;IACd,CAAC;YAAS,CAAC;QACT,IAAI,MAAM,EAAE,CAAC;YACX,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;YACvB,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;QACvB,CAAC;IACH,CAAC;AACH,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,KAAc;IACvC,iBAAiB,CAAC,OAAO,GAAG,KAAK,CAAC;AACpC,CAAC;AAED,SAAS,SAAS,CAAC,MAAmB;IACpC,IAAI,MAAM,CAAC,UAAU,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACnE,OAAO,IAAI,oBAAoB,CAAC;YAC9B,gBAAgB,EAAE,IAAI;YACtB,4BAA4B,EAAE,IAAI;YAClC,wBAAwB,EAAE,KAAK;YAC/B,UAAU,EAAE,MAAM,CAAC,UAAU;SAC9B,CAAC,CAAC;IACL,CAAC;SAAM,CAAC;QACN,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
@@ -11,14 +11,16 @@ import { invoke } from '#src/llmUtils.js';
11
11
  * @param content - The content of the question
12
12
  */
13
13
  export async function askQuestion(source, preamble, content) {
14
- const progressIndicator = new ProgressIndicator('Thinking.');
15
- const outputContent = await invoke(slothContext.config.llm, slothContext.session, preamble, content);
16
- progressIndicator.stop();
14
+ const progressIndicator = slothContext.config.streamOutput
15
+ ? undefined
16
+ : new ProgressIndicator('Thinking.');
17
+ const outputContent = await invoke(slothContext.config.llm, preamble, content, slothContext.config);
18
+ progressIndicator?.stop();
17
19
  const filename = generateStandardFileName(source);
18
20
  const filePath = getGslothFilePath(filename);
19
- display(`\nwriting ${filePath}`);
20
- // TODO highlight LLM output with something like Prism.JS (maybe system emoj are enough ✅⚠️❌)
21
- display('\n' + outputContent);
21
+ if (!slothContext.config.streamOutput) {
22
+ display('\n' + outputContent);
23
+ }
22
24
  try {
23
25
  writeFileSync(filePath, outputContent);
24
26
  displaySuccess(`This report can be found in ${filePath}`);
@@ -1 +1 @@
1
- {"version":3,"file":"questionAnsweringModule.js","sourceRoot":"","sources":["../../src/modules/questionAnsweringModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC7E,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EAAE,wBAAwB,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAC5E,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACxC,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAE1C;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,MAAc,EACd,QAAgB,EAChB,OAAe;IAEf,MAAM,iBAAiB,GAAG,IAAI,iBAAiB,CAAC,WAAW,CAAC,CAAC;IAC7D,MAAM,aAAa,GAAG,MAAM,MAAM,CAChC,YAAY,CAAC,MAAM,CAAC,GAAG,EACvB,YAAY,CAAC,OAAO,EACpB,QAAQ,EACR,OAAO,CACR,CAAC;IACF,iBAAiB,CAAC,IAAI,EAAE,CAAC;IACzB,MAAM,QAAQ,GAAG,wBAAwB,CAAC,MAAM,CAAC,CAAC;IAClD,MAAM,QAAQ,GAAG,iBAAiB,CAAC,QAAQ,CAAC,CAAC;IAC7C,OAAO,CAAC,aAAa,QAAQ,EAAE,CAAC,CAAC;IACjC,6FAA6F;IAC7F,OAAO,CAAC,IAAI,GAAG,aAAa,CAAC,CAAC;IAC9B,IAAI,CAAC;QACH,aAAa,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC;QACvC,cAAc,CAAC,+BAA+B,QAAQ,EAAE,CAAC,CAAC;IAC5D,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,YAAY,CAAC,mCAAmC,QAAQ,EAAE,CAAC,CAAC;QAC5D,YAAY,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QACrE,yDAAyD;QACzD,WAAW;IACb,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"questionAnsweringModule.js","sourceRoot":"","sources":["../../src/modules/questionAnsweringModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC7E,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EAAE,wBAAwB,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAC5E,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACxC,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAE1C;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,MAAc,EACd,QAAgB,EAChB,OAAe;IAEf,MAAM,iBAAiB,GAAG,YAAY,CAAC,MAAM,CAAC,YAAY;QACxD,CAAC,CAAC,SAAS;QACX,CAAC,CAAC,IAAI,iBAAiB,CAAC,WAAW,CAAC,CAAC;IACvC,MAAM,aAAa,GAAG,MAAM,MAAM,CAChC,YAAY,CAAC,MAAM,CAAC,GAAG,EACvB,QAAQ,EACR,OAAO,EACP,YAAY,CAAC,MAAM,CACpB,CAAC;IACF,iBAAiB,EAAE,IAAI,EAAE,CAAC;IAC1B,MAAM,QAAQ,GAAG,wBAAwB,CAAC,MAAM,CAAC,CAAC;IAClD,MAAM,QAAQ,GAAG,iBAAiB,CAAC,QAAQ,CAAC,CAAC;IAC7C,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,YAAY,EAAE,CAAC;QACtC,OAAO,CAAC,IAAI,GAAG,aAAa,CAAC,CAAC;IAChC,CAAC;IACD,IAAI,CAAC;QACH,aAAa,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC;QACvC,cAAc,CAAC,+BAA+B,QAAQ,EAAE,CAAC,CAAC;IAC5D,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,YAAY,CAAC,mCAAmC,QAAQ,EAAE,CAAC,CAAC;QAC5D,YAAY,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QACrE,yDAAyD;QACzD,WAAW;IACb,CAAC;AACH,CAAC"}
@@ -1,21 +1,20 @@
1
1
  import { slothContext } from '#src/config.js';
2
2
  import { display, displayDebug, displayError, displaySuccess } from '#src/consoleUtils.js';
3
- import { stdout } from '#src/systemUtils.js';
4
3
  import { generateStandardFileName, ProgressIndicator } from '#src/utils.js';
5
4
  import { writeFileSync } from 'node:fs';
6
5
  import { invoke } from '#src/llmUtils.js';
7
6
  import { getGslothFilePath } from '#src/filePathUtils.js';
8
7
  export async function review(source, preamble, diff) {
9
- const progressIndicator = new ProgressIndicator('Reviewing.');
10
- const outputContent = await invoke(slothContext.config.llm, slothContext.session, preamble, diff);
11
- progressIndicator.stop();
8
+ const progressIndicator = slothContext.config.streamOutput
9
+ ? undefined
10
+ : new ProgressIndicator('Reviewing.');
11
+ const outputContent = await invoke(slothContext.config.llm, preamble, diff, slothContext.config);
12
+ progressIndicator?.stop();
12
13
  const filename = generateStandardFileName(source);
13
14
  const filePath = getGslothFilePath(filename);
14
- stdout.write('\n');
15
- display(`writing ${filePath}`);
16
- stdout.write('\n');
17
- // TODO highlight LLM output with something like Prism.JS (maybe system emoj are enough ✅⚠️❌)
18
- display(outputContent);
15
+ if (!slothContext.config.streamOutput) {
16
+ display('\n' + outputContent);
17
+ }
19
18
  try {
20
19
  writeFileSync(filePath, outputContent);
21
20
  displaySuccess(`This report can be found in ${filePath}`);
@@ -1 +1 @@
1
- {"version":3,"file":"reviewModule.js","sourceRoot":"","sources":["../../src/modules/reviewModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3F,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC7C,OAAO,EAAE,wBAAwB,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAC5E,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACxC,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC1C,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAE1D,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,MAAc,EAAE,QAAgB,EAAE,IAAY;IACzE,MAAM,iBAAiB,GAAG,IAAI,iBAAiB,CAAC,YAAY,CAAC,CAAC;IAC9D,MAAM,aAAa,GAAG,MAAM,MAAM,CAAC,YAAY,CAAC,MAAM,CAAC,GAAG,EAAE,YAAY,CAAC,OAAO,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;IAClG,iBAAiB,CAAC,IAAI,EAAE,CAAC;IACzB,MAAM,QAAQ,GAAG,wBAAwB,CAAC,MAAM,CAAC,CAAC;IAClD,MAAM,QAAQ,GAAG,iBAAiB,CAAC,QAAQ,CAAC,CAAC;IAC7C,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACnB,OAAO,CAAC,WAAW,QAAQ,EAAE,CAAC,CAAC;IAC/B,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACnB,6FAA6F;IAC7F,OAAO,CAAC,aAAa,CAAC,CAAC;IACvB,IAAI,CAAC;QACH,aAAa,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC;QACvC,cAAc,CAAC,+BAA+B,QAAQ,EAAE,CAAC,CAAC;IAC5D,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,YAAY,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QAC7D,YAAY,CAAC,mCAAmC,QAAQ,EAAE,CAAC,CAAC;QAC5D,qDAAqD;QACrD,WAAW;IACb,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"reviewModule.js","sourceRoot":"","sources":["../../src/modules/reviewModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3F,OAAO,EAAE,wBAAwB,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAC5E,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACxC,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC1C,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAE1D,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,MAAc,EAAE,QAAgB,EAAE,IAAY;IACzE,MAAM,iBAAiB,GAAG,YAAY,CAAC,MAAM,CAAC,YAAY;QACxD,CAAC,CAAC,SAAS;QACX,CAAC,CAAC,IAAI,iBAAiB,CAAC,YAAY,CAAC,CAAC;IACxC,MAAM,aAAa,GAAG,MAAM,MAAM,CAAC,YAAY,CAAC,MAAM,CAAC,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,CAAC,MAAM,CAAC,CAAC;IACjG,iBAAiB,EAAE,IAAI,EAAE,CAAC;IAC1B,MAAM,QAAQ,GAAG,wBAAwB,CAAC,MAAM,CAAC,CAAC;IAClD,MAAM,QAAQ,GAAG,iBAAiB,CAAC,QAAQ,CAAC,CAAC;IAC7C,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,YAAY,EAAE,CAAC;QACtC,OAAO,CAAC,IAAI,GAAG,aAAa,CAAC,CAAC;IAChC,CAAC;IACD,IAAI,CAAC;QACH,aAAa,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC;QACvC,cAAc,CAAC,+BAA+B,QAAQ,EAAE,CAAC,CAAC;IAC5D,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,YAAY,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QAC7D,YAAY,CAAC,mCAAmC,QAAQ,EAAE,CAAC,CAAC;QAC5D,qDAAqD;QACrD,WAAW;IACb,CAAC;AACH,CAAC"}
@@ -1,5 +1,6 @@
1
1
  import { display, displayError, displayWarning } from '#src/consoleUtils.js';
2
2
  import { env } from '#src/systemUtils.js';
3
+ import { ProgressIndicator } from '#src/utils.js';
3
4
  /**
4
5
  * Gets Jira issue using Atlassian REST API v3 with Personal Access Token
5
6
  *
@@ -72,7 +73,6 @@ async function getJiraIssue(config, jiraKey) {
72
73
  if (config.displayUrl) {
73
74
  display(`Loading Jira issue ${config.displayUrl}${jiraKey}`);
74
75
  }
75
- display(`Retrieving jira from api ${apiUrl.replace(/^https?:\/\//, '')}`);
76
76
  // This filter will be necessary for V3: `&expand=renderedFields` to convert ADF to HTML
77
77
  const filters = '?fields=summary,description'; // Limit JSON to summary and description
78
78
  // Encode credentials for Basic Authentication header
@@ -85,10 +85,12 @@ async function getJiraIssue(config, jiraKey) {
85
85
  Accept: 'application/json; charset=utf-8',
86
86
  'Accept-Language': 'en-US,en;q=0.9', // Prevents errors in other languages
87
87
  };
88
+ const progressIndicator = new ProgressIndicator(`Retrieving jira from api ${apiUrl.replace(/^https?:\/\//, '')}`);
88
89
  const response = await fetch(apiUrl + filters, {
89
90
  method: 'GET',
90
91
  headers: headers,
91
92
  });
93
+ progressIndicator.stop();
92
94
  if (!response?.ok) {
93
95
  try {
94
96
  const errorData = await response.json();
@@ -1 +1 @@
1
- {"version":3,"file":"jiraIssueProvider.js","sourceRoot":"","sources":["../../src/providers/jiraIssueProvider.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"jiraIssueProvider.js","sourceRoot":"","sources":["../../src/providers/jiraIssueProvider.ts"],"names":[],"mappings":"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"}
@@ -39,35 +39,37 @@ If the `.gsloth` directory doesn't exist, gsloth will continue writing all files
39
39
 
40
40
  It is always worth checking sourcecode in [config.ts](../src/config.ts) for more insightful information.
41
41
 
42
- | Parameter | Required | Default Value | Description |
43
- |------------------------------------------|-----------------------------------|---------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
42
+ | Parameter | Required | Default Value | Description |
43
+ |------------------------------------------|-----------------------------------|---------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
44
44
  | `llm` | Required | - | An object configuring LLM. In JS config could be actual instance of LangChainJS [BaseChatModel](https://v03.api.js.langchain.com/classes/_langchain_core.language_models_chat_models.BaseChatModel.html), allowing to use LLMs which do not have a preset. |
45
- | `llm.type` | Required (when using JSON config) | - | LLM type or provider. Options currently available are `anthropic`, `groq` and `vertexai`. To use other models supported by LangChainJS, please use JavaScript config. |
46
- | `llm.model` | Optional | - | Particular LLM model string (Check in your provider documentation). |
47
- | `llm.apiKey` | Optional | - | API key for the LLM provider. You can either use this parameter or use environment variable. |
48
- | `contentProvider` | Optional | `file` | Default content provider used to get content for review. Options available are `github`, `file` and `text` (`text` provides text as it is). |
49
- | `requirementsProvider` | Optional | `file` | Default requirements provider used to get requirements for review. Options available are `jira`, `jira-legacy`, `github`, `file` and `text`. |
45
+ | `llm.type` | Required (when using JSON config) | - | LLM type or provider. Options currently available are `anthropic`, `groq` and `vertexai`. To use other models supported by LangChainJS, please use JavaScript config. |
46
+ | `llm.model` | Optional | - | Particular LLM model string (Check in your provider documentation). |
47
+ | `llm.apiKey` | Optional | - | API key for the LLM provider. You can either use this parameter or use environment variable. |
48
+ | `contentProvider` | Optional | `file` | Default content provider used to get content for review. Options available are `github`, `file` and `text` (`text` provides text as it is). |
49
+ | `requirementsProvider` | Optional | `file` | Default requirements provider used to get requirements for review. Options available are `jira`, `jira-legacy`, `github`, `file` and `text`. |
50
50
  | `projectGuidelines` | Optional | `.gsloth.guidelines.md` | Path to the file containing project guidelines. |
51
- | `projectReviewInstructions` | Optional | `.gsloth.review.md` | Path to the file containing project review instructions. |
52
- | `commands` | Optional | - | Configuration for specific commands. |
53
- | `commands.pr` | Optional | - | Configuration for the PR command. |
54
- | `commands.pr.contentProvider` | Optional | `github` | Content provider used for PR review (`gsloth pr`). |
55
- | `commands.pr.requirementsProvider` | Optional | `github` | Requirements provider used for PR review. If not specified, falls back to the global `requirementsProvider`. |
56
- | `commands.review` | Optional | - | Configuration for the review command. |
57
- | `commands.review.contentProvider` | Optional | - | Content provider specifically for the review command. If not specified, falls back to the global `contentProvider`. |
58
- | `commands.review.requirementsProvider` | Optional | - | Requirements provider specifically for the review command. If not specified, falls back to the global `requirementsProvider`. |
59
- | `requirementsProviderConfig` | Optional | - | Configuration for requirements providers. Contains provider-specific configurations. |
60
- | `requirementsProviderConfig.jira` | Optional | - | Configuration for the Jira requirements provider (Atlassian REST API v3 with Personal Access Token). |
61
- | `requirementsProviderConfig.jira.username` | Optional | - | Jira username (email). Can also be set via JIRA_USERNAME environment variable. |
62
- | `requirementsProviderConfig.jira.token` | Optional | - | Jira Personal Access Token. Can also be set via JIRA_API_PAT_TOKEN environment variable. |
63
- | `requirementsProviderConfig.jira.cloudId` | Required for `jira` | - | Atlassian Cloud ID. Can also be set via JIRA_CLOUD_ID environment variable. |
64
- | `requirementsProviderConfig.jira.displayUrl` | Optional | - | Optional URL for displaying Jira issues (e.g., "https://yourcompany.atlassian.net/browse/"). |
65
- | `requirementsProviderConfig.jira-legacy` | Optional | - | Configuration for the Jira Legacy requirements provider (Atlassian REST API v2 with Legacy API Token). |
66
- | `requirementsProviderConfig.jira-legacy.username` | Optional | - | Jira username (email). Can also be set via JIRA_USERNAME environment variable. |
67
- | `requirementsProviderConfig.jira-legacy.token` | Optional | - | Jira Legacy API Token. Can also be set via JIRA_LEGACY_API_TOKEN environment variable. |
51
+ | `projectReviewInstructions` | Optional | `.gsloth.review.md` | Path to the file containing project review instructions. |
52
+ | `streamOutput` | Optional | `true` | When set to `true`, AI responses are streamed to the console in real-time. When `false`, responses are displayed only after completion. |
53
+ | `commands` | Optional | - | Configuration for specific commands. |
54
+ | `commands.pr` | Optional | - | Configuration for the PR command. |
55
+ | `commands.pr.contentProvider` | Optional | `github` | Content provider used for PR review (`gsloth pr`). |
56
+ | `commands.pr.requirementsProvider` | Optional | `github` | Requirements provider used for PR review. If not specified, falls back to the global `requirementsProvider`. |
57
+ | `commands.review` | Optional | - | Configuration for the review command. |
58
+ | `commands.review.contentProvider` | Optional | - | Content provider specifically for the review command. If not specified, falls back to the global `contentProvider`. |
59
+ | `commands.review.requirementsProvider` | Optional | - | Requirements provider specifically for the review command. If not specified, falls back to the global `requirementsProvider`. |
60
+ | `requirementsProviderConfig` | Optional | - | Configuration for requirements providers. Contains provider-specific configurations. |
61
+ | `requirementsProviderConfig.jira` | Optional | - | Configuration for the Jira requirements provider (Atlassian REST API v3 with Personal Access Token). |
62
+ | `requirementsProviderConfig.jira.username` | Optional | - | Jira username (email). Can also be set via JIRA_USERNAME environment variable. |
63
+ | `requirementsProviderConfig.jira.token` | Optional | - | Jira Personal Access Token. Can also be set via JIRA_API_PAT_TOKEN environment variable. |
64
+ | `requirementsProviderConfig.jira.cloudId` | Required for `jira` | - | Atlassian Cloud ID. Can also be set via JIRA_CLOUD_ID environment variable. |
65
+ | `requirementsProviderConfig.jira.displayUrl` | Optional | - | Optional URL for displaying Jira issues (e.g., "https://yourcompany.atlassian.net/browse/"). |
66
+ | `requirementsProviderConfig.jira-legacy` | Optional | - | Configuration for the Jira Legacy requirements provider (Atlassian REST API v2 with Legacy API Token). |
67
+ | `requirementsProviderConfig.jira-legacy.username` | Optional | - | Jira username (email). Can also be set via JIRA_USERNAME environment variable. |
68
+ | `requirementsProviderConfig.jira-legacy.token` | Optional | - | Jira Legacy API Token. Can also be set via JIRA_LEGACY_API_TOKEN environment variable. |
68
69
  | `requirementsProviderConfig.jira-legacy.baseUrl` | Required for `jira-legacy` | - | Base URL for the Jira API (e.g., "https://yourcompany.atlassian.net/rest/api/2/issue/"). |
69
- | `requirementsProviderConfig.jira-legacy.displayUrl` | Optional | - | Optional URL for displaying Jira issues (e.g., "https://yourcompany.atlassian.net/browse/"). |
70
- | `contentProviderConfig` | Optional | - | Configuration for content providers. Currently, the available content providers (`github`, `file`, and `text`) don't require specific configuration. |
70
+ | `requirementsProviderConfig.jira-legacy.displayUrl` | Optional | - | Optional URL for displaying Jira issues (e.g., "https://yourcompany.atlassian.net/browse/"). |
71
+ | `contentProviderConfig` | Optional | - | Configuration for content providers. Currently, the available content providers (`github`, `file`, and `text`) don't require specific configuration. |
72
+ | `mcpServers` | Optional | - | Configuration for Model Context Protocol (MCP) servers. This allows for enhanced context management. |
71
73
 
72
74
  ## Config initialization
73
75
  Configuration can be created with `gsloth init [vendor]` command.
@@ -195,6 +197,38 @@ export async function configure(importFunction, global) {
195
197
  The configure function should simply return instance of langchain [chat model](https://v03.api.js.langchain.com/classes/_langchain_core.language_models_chat_models.BaseChatModel.html).
196
198
  See [Langchain documentation](https://js.langchain.com/docs/tutorials/llm_chain/) for more details.
197
199
 
200
+ ## Model Context Protocol (MCP)
201
+
202
+ Gaunt Sloth Assistant supports the Model Context Protocol (MCP), which provides enhanced context management.
203
+ The `@modelcontextprotocol/server-filesystem` package is included as a dependency, allowing you to easily configure file system access for your LLM.
204
+
205
+ ### MCP Filesystem Server Configuration
206
+
207
+ To configure the MCP filesystem server, add the `mcpServers` section to your configuration file:
208
+
209
+ ```json
210
+ {
211
+ "llm": {
212
+ "type": "vertexai",
213
+ "model": "gemini-2.5-pro-preview-05-06",
214
+ "temperature": 0
215
+ },
216
+ "mcpServers": {
217
+ "filesystem": {
218
+ "transport": "stdio",
219
+ "command": "npx",
220
+ "args": [
221
+ "-y",
222
+ "@modelcontextprotocol/server-filesystem",
223
+ "/home/path/to/your/files"
224
+ ]
225
+ }
226
+ }
227
+ }
228
+ ```
229
+
230
+ This configuration launches the MCP filesystem server using npx, providing the LLM with access to the specified directory. The server uses stdio for communication with the LLM.
231
+
198
232
  ## Content providers
199
233
 
200
234
  ### GitHub Issues
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gaunt-sloth-assistant",
3
- "version": "0.4.2",
3
+ "version": "0.5.0",
4
4
  "description": "",
5
5
  "license": "MIT",
6
6
  "author": "Andrew Kondratev",
@@ -29,6 +29,8 @@
29
29
  "@langchain/google-vertexai": "^0.2.8",
30
30
  "@langchain/groq": "^0.2.2",
31
31
  "@langchain/langgraph": "^0.2.71",
32
+ "@langchain/mcp-adapters": "^0.4.5",
33
+ "@modelcontextprotocol/server-filesystem": "^2025.3.28",
32
34
  "chalk": "^5.4.1",
33
35
  "commander": "^14.0.0",
34
36
  "uuid": "^11.1.0"
package/src/config.ts CHANGED
@@ -1,10 +1,10 @@
1
- import { v4 as uuidv4 } from 'uuid';
2
1
  import { displayDebug, displayError, displayInfo, displayWarning } from '#src/consoleUtils.js';
3
2
  import { importExternalFile, writeFileIfNotExistsWithMessages } from '#src/utils.js';
4
3
  import { existsSync, readFileSync } from 'node:fs';
5
4
  import { error, exit } from '#src/systemUtils.js';
6
5
  import type { BaseChatModel } from '@langchain/core/language_models/chat_models';
7
- import { getGslothConfigWritePath, getGslothConfigReadPath } from '#src/filePathUtils.js';
6
+ import { getGslothConfigReadPath, getGslothConfigWritePath } from '#src/filePathUtils.js';
7
+ import type { Connection } from '@langchain/mcp-adapters';
8
8
 
9
9
  export interface SlothConfig extends BaseSlothConfig {
10
10
  llm: BaseChatModel; // FIXME this is still bad keeping instance in config is probably not best choice
@@ -12,6 +12,7 @@ export interface SlothConfig extends BaseSlothConfig {
12
12
  requirementsProvider: string;
13
13
  projectGuidelines: string;
14
14
  projectReviewInstructions: string;
15
+ streamOutput: boolean;
15
16
  commands: {
16
17
  pr: {
17
18
  contentProvider: string;
@@ -40,6 +41,7 @@ interface BaseSlothConfig {
40
41
  requirementsProvider?: string;
41
42
  projectGuidelines?: string;
42
43
  projectReviewInstructions?: string;
44
+ streamOutput?: boolean;
43
45
  commands?: {
44
46
  pr: {
45
47
  contentProvider: string;
@@ -52,6 +54,7 @@ interface BaseSlothConfig {
52
54
  };
53
55
  requirementsProviderConfig?: Record<string, unknown>;
54
56
  contentProviderConfig?: Record<string, unknown>;
57
+ mcpServers?: Record<string, Connection>;
55
58
  }
56
59
 
57
60
  /**
@@ -60,11 +63,6 @@ interface BaseSlothConfig {
60
63
  */
61
64
  export interface SlothContext {
62
65
  config: SlothConfig;
63
- session: {
64
- configurable: {
65
- thread_id: string;
66
- };
67
- };
68
66
  }
69
67
 
70
68
  export interface LLMConfig extends Record<string, unknown> {
@@ -88,6 +86,7 @@ export const DEFAULT_CONFIG: Partial<SlothConfig> = {
88
86
  requirementsProvider: 'file',
89
87
  projectGuidelines: PROJECT_GUIDELINES,
90
88
  projectReviewInstructions: PROJECT_REVIEW_INSTRUCTIONS,
89
+ streamOutput: true,
91
90
  commands: {
92
91
  pr: {
93
92
  contentProvider: 'github', // gh pr diff NN
@@ -103,7 +102,6 @@ export const DEFAULT_CONFIG: Partial<SlothConfig> = {
103
102
  */
104
103
  export const slothContext = {
105
104
  config: DEFAULT_CONFIG,
106
- session: { configurable: { thread_id: uuidv4() } },
107
105
  } as Partial<SlothContext> as SlothContext;
108
106
 
109
107
  export async function initConfig(): Promise<void> {
@@ -114,6 +112,7 @@ export async function initConfig(): Promise<void> {
114
112
  // Try loading JSON config file first
115
113
  if (existsSync(jsonConfigPath)) {
116
114
  try {
115
+ // TODO makes sense to employ ZOD to validate config
117
116
  const jsonConfig = JSON.parse(readFileSync(jsonConfigPath, 'utf8')) as RawSlothConfig;
118
117
  // If the config has an LLM with a type, create the appropriate LLM instance
119
118
  if (jsonConfig.llm && typeof jsonConfig.llm === 'object' && 'type' in jsonConfig.llm) {
@@ -296,5 +295,4 @@ export function reset() {
296
295
  delete (slothContext as unknown as Record<string, unknown>)[key];
297
296
  });
298
297
  slothContext.config = DEFAULT_CONFIG as SlothConfig;
299
- slothContext.session = { configurable: { thread_id: uuidv4() } };
300
298
  }
package/src/llmUtils.ts CHANGED
@@ -1,8 +1,11 @@
1
- import type { Message, State } from '#src/modules/types.js';
2
- import { AIMessageChunk, HumanMessage, SystemMessage } from '@langchain/core/messages';
1
+ import type { Message } from '#src/modules/types.js';
2
+ import { HumanMessage, isAIMessageChunk, SystemMessage } from '@langchain/core/messages';
3
3
  import { BaseChatModel } from '@langchain/core/language_models/chat_models';
4
- import { END, MemorySaver, MessagesAnnotation, START, StateGraph } from '@langchain/langgraph';
5
- import { BaseLanguageModelCallOptions } from '@langchain/core/language_models/base';
4
+ import { SlothConfig } from '#src/config.js';
5
+ import { MultiServerMCPClient } from '@langchain/mcp-adapters';
6
+ import { display, displayError, displayInfo } from '#src/consoleUtils.js';
7
+ import { createReactAgent } from '@langchain/langgraph/prebuilt';
8
+ import { stdout } from '#src/systemUtils.js';
6
9
 
7
10
  const llmGlobalSettings = {
8
11
  verbose: false,
@@ -10,45 +13,78 @@ const llmGlobalSettings = {
10
13
 
11
14
  export async function invoke(
12
15
  llm: BaseChatModel,
13
- options: Partial<BaseLanguageModelCallOptions>,
14
16
  systemMessage: string,
15
- prompt: string
17
+ prompt: string,
18
+ config: SlothConfig
16
19
  ): Promise<string> {
17
20
  if (llmGlobalSettings.verbose) {
18
21
  llm.verbose = true;
19
22
  }
20
- // This node receives the current state (messages) and invokes the LLM
21
- const callModel = async (state: State): Promise<{ messages: AIMessageChunk }> => {
22
- // state.messages will contain the list including the system systemMessage and user diff
23
- const response = await (llm as BaseChatModel).invoke(state.messages);
24
- // MessagesAnnotation expects the node to return the new message(s) to be added to the state.
25
- // Wrap the response in an array if it's a single message object.
26
- return { messages: response };
27
- };
28
-
29
- // Define the graph structure with MessagesAnnotation state
30
- const workflow = new StateGraph(MessagesAnnotation)
31
- // Define the node and edge
32
- .addNode('model', callModel)
33
- .addEdge(START, 'model') // Start at the 'model' node
34
- .addEdge('model', END); // End after the 'model' node completes
35
-
36
- // Set up memory (optional but good practice for potential future multi-turn interactions)
37
- const memory = new MemorySaver();
38
-
39
- // Compile the workflow into a runnable app
40
- const app = workflow.compile({ checkpointer: memory });
41
-
42
- // Construct the initial the messages including the systemMessage as a system message
43
- const messages: Message[] = [new SystemMessage(systemMessage), new HumanMessage(prompt)];
44
-
45
- const output = await app.invoke({ messages }, options);
46
- const lastMessage = output.messages[output.messages.length - 1];
47
- return typeof lastMessage.content === 'string'
48
- ? lastMessage.content
49
- : JSON.stringify(lastMessage.content);
23
+
24
+ const client = getClient(config);
25
+
26
+ const tools = (await client?.getTools()) ?? [];
27
+ if (tools && tools.length > 0) {
28
+ displayInfo(`Loaded ${tools.length} MCP tools.`);
29
+ }
30
+
31
+ // Create the React agent
32
+ const agent = createReactAgent({
33
+ llm,
34
+ tools,
35
+ });
36
+
37
+ // Run the agent
38
+ try {
39
+ const messages: Message[] = [new SystemMessage(systemMessage), new HumanMessage(prompt)];
40
+ display(`Connecting to LLM...`);
41
+ const stream = await agent.stream({ messages }, { streamMode: 'messages' });
42
+
43
+ const output = { aiMessage: '' };
44
+ for await (const [chunk, _metadata] of stream) {
45
+ if (isAIMessageChunk(chunk)) {
46
+ if (config.streamOutput) {
47
+ stdout.write(chunk.content as string, 'utf-8');
48
+ }
49
+ output.aiMessage += chunk.content;
50
+ let toolCalls = chunk.tool_calls;
51
+ if (toolCalls && toolCalls.length > 0) {
52
+ const suffix = toolCalls.length > 1 ? 's' : '';
53
+ const toolCallsString = toolCalls.map((t) => t?.name).join(', ');
54
+ displayInfo(`Using tool${suffix} ${toolCallsString}`);
55
+ }
56
+ }
57
+ }
58
+
59
+ return output.aiMessage;
60
+ } catch (error) {
61
+ if (error instanceof Error) {
62
+ if (error?.name === 'ToolException') {
63
+ displayError(`Tool execution failed: ${error.message}`);
64
+ }
65
+ }
66
+ throw error;
67
+ } finally {
68
+ if (client) {
69
+ console.log('closing');
70
+ await client.close();
71
+ }
72
+ }
50
73
  }
51
74
 
52
75
  export function setVerbose(debug: boolean) {
53
76
  llmGlobalSettings.verbose = debug;
54
77
  }
78
+
79
+ function getClient(config: SlothConfig) {
80
+ if (config.mcpServers && Object.keys(config.mcpServers).length > 0) {
81
+ return new MultiServerMCPClient({
82
+ throwOnLoadError: true,
83
+ prefixToolNameWithServerName: true,
84
+ additionalToolNamePrefix: 'mcp',
85
+ mcpServers: config.mcpServers,
86
+ });
87
+ } else {
88
+ return null;
89
+ }
90
+ }
@@ -16,19 +16,21 @@ export async function askQuestion(
16
16
  preamble: string,
17
17
  content: string
18
18
  ): Promise<void> {
19
- const progressIndicator = new ProgressIndicator('Thinking.');
19
+ const progressIndicator = slothContext.config.streamOutput
20
+ ? undefined
21
+ : new ProgressIndicator('Thinking.');
20
22
  const outputContent = await invoke(
21
23
  slothContext.config.llm,
22
- slothContext.session,
23
24
  preamble,
24
- content
25
+ content,
26
+ slothContext.config
25
27
  );
26
- progressIndicator.stop();
28
+ progressIndicator?.stop();
27
29
  const filename = generateStandardFileName(source);
28
30
  const filePath = getGslothFilePath(filename);
29
- display(`\nwriting ${filePath}`);
30
- // TODO highlight LLM output with something like Prism.JS (maybe system emoj are enough ✅⚠️❌)
31
- display('\n' + outputContent);
31
+ if (!slothContext.config.streamOutput) {
32
+ display('\n' + outputContent);
33
+ }
32
34
  try {
33
35
  writeFileSync(filePath, outputContent);
34
36
  displaySuccess(`This report can be found in ${filePath}`);
@@ -1,22 +1,21 @@
1
1
  import { slothContext } from '#src/config.js';
2
2
  import { display, displayDebug, displayError, displaySuccess } from '#src/consoleUtils.js';
3
- import { stdout } from '#src/systemUtils.js';
4
3
  import { generateStandardFileName, ProgressIndicator } from '#src/utils.js';
5
4
  import { writeFileSync } from 'node:fs';
6
5
  import { invoke } from '#src/llmUtils.js';
7
6
  import { getGslothFilePath } from '#src/filePathUtils.js';
8
7
 
9
8
  export async function review(source: string, preamble: string, diff: string): Promise<void> {
10
- const progressIndicator = new ProgressIndicator('Reviewing.');
11
- const outputContent = await invoke(slothContext.config.llm, slothContext.session, preamble, diff);
12
- progressIndicator.stop();
9
+ const progressIndicator = slothContext.config.streamOutput
10
+ ? undefined
11
+ : new ProgressIndicator('Reviewing.');
12
+ const outputContent = await invoke(slothContext.config.llm, preamble, diff, slothContext.config);
13
+ progressIndicator?.stop();
13
14
  const filename = generateStandardFileName(source);
14
15
  const filePath = getGslothFilePath(filename);
15
- stdout.write('\n');
16
- display(`writing ${filePath}`);
17
- stdout.write('\n');
18
- // TODO highlight LLM output with something like Prism.JS (maybe system emoj are enough ✅⚠️❌)
19
- display(outputContent);
16
+ if (!slothContext.config.streamOutput) {
17
+ display('\n' + outputContent);
18
+ }
20
19
  try {
21
20
  writeFileSync(filePath, outputContent);
22
21
  displaySuccess(`This report can be found in ${filePath}`);
@@ -1,6 +1,7 @@
1
1
  import { display, displayError, displayWarning } from '#src/consoleUtils.js';
2
2
  import { env } from '#src/systemUtils.js';
3
3
  import type { JiraConfig } from './types.js';
4
+ import { ProgressIndicator } from '#src/utils.js';
4
5
 
5
6
  interface JiraIssueResponse {
6
7
  fields: {
@@ -105,7 +106,6 @@ async function getJiraIssue(config: JiraConfig, jiraKey: string): Promise<JiraIs
105
106
  if (config.displayUrl) {
106
107
  display(`Loading Jira issue ${config.displayUrl}${jiraKey}`);
107
108
  }
108
- display(`Retrieving jira from api ${apiUrl.replace(/^https?:\/\//, '')}`);
109
109
 
110
110
  // This filter will be necessary for V3: `&expand=renderedFields` to convert ADF to HTML
111
111
  const filters = '?fields=summary,description'; // Limit JSON to summary and description
@@ -122,10 +122,14 @@ async function getJiraIssue(config: JiraConfig, jiraKey: string): Promise<JiraIs
122
122
  'Accept-Language': 'en-US,en;q=0.9', // Prevents errors in other languages
123
123
  };
124
124
 
125
+ const progressIndicator = new ProgressIndicator(
126
+ `Retrieving jira from api ${apiUrl.replace(/^https?:\/\//, '')}`
127
+ );
125
128
  const response = await fetch(apiUrl + filters, {
126
129
  method: 'GET',
127
130
  headers: headers,
128
131
  });
132
+ progressIndicator.stop();
129
133
 
130
134
  if (!response?.ok) {
131
135
  try {