From 2e5282c9385a7bd30c6e815e68ff094cb894dd79 Mon Sep 17 00:00:00 2001 From: Lucas Carlson Date: Tue, 27 Aug 2024 10:58:16 -0700 Subject: [PATCH 1/2] Enhance DocsManager with continuous documentation generation - Add fullDocs property to store complete documentation - Implement recursive documentation generation until completion - Update finalizeResponse method to handle continuous generation - Improve block applicability check using full documentation --- src/managers/DocsManager.ts | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/managers/DocsManager.ts b/src/managers/DocsManager.ts index d051f86..83baa6b 100644 --- a/src/managers/DocsManager.ts +++ b/src/managers/DocsManager.ts @@ -17,6 +17,8 @@ import StreamManager from './StreamManager' * Manages the generation of documentation for specified files. */ class DocsManager extends StreamManager { + private fullDocs = '' + /** * Creates a new DocumentationManager instance. * @param {ClovingGPTOptions} options - Configuration options for the DocumentationManager. @@ -58,11 +60,26 @@ class DocsManager extends StreamManager { * @protected */ protected async finalizeResponse(): Promise { + this.fullDocs += `${this.responseString}\n\n` this.addAssistantResponse(this.responseString) this.isProcessing = false - if (this.responseString !== '') { - const currentNewBlocks = extractCurrentNewBlocks(this.responseString) + if (!this.responseString.includes('======= DONE =======')) { + console.log(colors.yellow('Checking if there is more...')) + this.addUserPrompt( + "If there is more, continue, otherwise print the string '======= DONE ======='.", + ) + const responseStream = await this.gpt.streamText({ + prompt: this.prompt, + messages: this.chatHistory, + }) + + this.handleResponseStream(responseStream) + return + } + + if (this.fullDocs !== '') { + const currentNewBlocks = extractCurrentNewBlocks(this.fullDocs) const [canApply, summary] = await checkBlocksApplicability(currentNewBlocks) if (canApply && currentNewBlocks.length > 0) { const shouldSave = await confirm({ From 32a78f2601d3c098aea43d67c4b3bc35cb06b1da Mon Sep 17 00:00:00 2001 From: Lucas Carlson Date: Tue, 27 Aug 2024 11:21:06 -0700 Subject: [PATCH 2/2] Enhance BlockManager and improve response handling - Add JSDoc comments to BlockManager for better code documentation - Implement continuous response handling in ChatManager and CodeManager - Update DocsManager to use fullResponse instead of fullDocs - Introduce fullResponse property in StreamManager for complete response tracking --- src/managers/BlockManager.ts | 39 ++++++++++++++++++++++++++++++----- src/managers/ChatManager.ts | 29 ++++++++++++++++++-------- src/managers/CodeManager.ts | 24 ++++++++++++++++++--- src/managers/DocsManager.ts | 9 ++++---- src/managers/StreamManager.ts | 1 + 5 files changed, 80 insertions(+), 22 deletions(-) diff --git a/src/managers/BlockManager.ts b/src/managers/BlockManager.ts index ae86fe1..4ee8a57 100644 --- a/src/managers/BlockManager.ts +++ b/src/managers/BlockManager.ts @@ -2,15 +2,27 @@ import { EventEmitter } from 'events' import { extractCurrentNewBlocks } from '../utils/string_utils' import type { CurrentNewBlock } from '../utils/types' -// Passes through string chunks, looking for code blocks, when it finds one, it starts buffering until it finds the end of the block -// Then it emits the code block and clears the buffer and continues +/** + * BlockManager class + * + * This class extends EventEmitter and manages the processing of code blocks within a stream of content. + * It passes through string chunks, looking for code blocks. When it finds one, it starts buffering + * until it finds the end of the block. Then it emits the code block, clears the buffer, and continues. + */ class BlockManager extends EventEmitter { + /** Stores non-code content */ private buffer: string = '' + /** Stores code block content */ private codeBuffer: string = '' + /** Indicates whether currently buffering a code block */ private isBufferingCode: boolean = false + /** Indicates whether waiting for more content to complete a block */ private isWaitingForContent: boolean = false - // add content to the buffer, watching for code blocks along the way + /** + * Adds content to the buffer, watching for code blocks along the way. + * @param {string} content - The content to be added and processed. + */ addContent(content: string) { if (content.includes('`') || content.includes('\n')) { this.isWaitingForContent = true @@ -36,6 +48,11 @@ class BlockManager extends EventEmitter { } } + /** + * Processes the content for code blocks. + * @param {string} content - The content to be processed for code blocks. + * @private + */ private processCodeBlocks(content: string) { const codeBlockMarker = '\n```' let markerIndex = content.indexOf(codeBlockMarker) @@ -66,6 +83,11 @@ class BlockManager extends EventEmitter { } } + /** + * Emits the buffered content as an event. + * @param {string} additionalContent - Additional content to be emitted with the buffer. + * @private + */ private emitBuffer(additionalContent: string = '') { const contentToEmit = this.buffer + additionalContent if (contentToEmit) { @@ -74,6 +96,10 @@ class BlockManager extends EventEmitter { } } + /** + * Emits the buffered code block as an event. + * @private + */ private emitCodeBlock() { if (this.codeBuffer.length > 0) { const currentNewBlock = this.parseCodeBuffer() @@ -93,8 +119,8 @@ class BlockManager extends EventEmitter { * current start index, divider index, and new end index. It then extracts the current code and new code * from the buffer based on these indices. * - * @return {CurrentNewBlock | null} - * An object containing the language, current start, new end, current code, and new code. + * @return {CurrentNewBlock | null} An object containing the language, current start, new end, current code, and new code. + * @private */ private parseCodeBuffer(): CurrentNewBlock | null { const results = extractCurrentNewBlocks(this.codeBuffer) @@ -102,6 +128,9 @@ class BlockManager extends EventEmitter { return results[0] } + /** + * Clears all buffers and resets state flags. + */ clearBuffer() { this.buffer = '' this.codeBuffer = '' diff --git a/src/managers/ChatManager.ts b/src/managers/ChatManager.ts index 646964c..a5f5898 100644 --- a/src/managers/ChatManager.ts +++ b/src/managers/ChatManager.ts @@ -455,13 +455,8 @@ class ChatManager extends StreamManager { } private async handleSave() { - const lastResponse = this.chatHistory - .slice() - .reverse() - .find((msg) => msg.role === 'assistant') - - if (lastResponse) { - const currentNewBlocks = extractCurrentNewBlocks(lastResponse.content) + if (this.fullResponse) { + const currentNewBlocks = extractCurrentNewBlocks(this.fullResponse) if (Object.keys(currentNewBlocks).length > 0) { await applyAndSaveCurrentNewBlocks(currentNewBlocks) console.info(`\n${colors.bold('save')} has finished\n`) @@ -510,6 +505,7 @@ class ChatManager extends StreamManager { this.isProcessing = true try { + this.fullResponse = '' await this.refreshContext() this.addUserPrompt(this.generatePrompt(input)) @@ -588,11 +584,26 @@ class ChatManager extends StreamManager { } protected async finalizeResponse(): Promise { + console.log('\n') + this.fullResponse += `${this.responseString}\n\n` this.addAssistantResponse(this.responseString) this.isProcessing = false - if (this.responseString !== '') { - const currentNewBlocks = extractCurrentNewBlocks(this.responseString) + if (!this.responseString.includes('======= DONE =======')) { + this.addUserPrompt( + "If there is more, continue, otherwise print the string '======= DONE ======='.", + ) + const responseStream = await this.gpt.streamText({ + prompt: this.prompt, + messages: this.chatHistory, + }) + + this.handleResponseStream(responseStream) + return + } + + if (this.fullResponse !== '') { + const currentNewBlocks = extractCurrentNewBlocks(this.fullResponse) const [canApply, summary] = await checkBlocksApplicability(currentNewBlocks) if (!canApply) { if (this.retryCount < this.maxRetries) { diff --git a/src/managers/CodeManager.ts b/src/managers/CodeManager.ts index 1ef3e8b..68143f0 100644 --- a/src/managers/CodeManager.ts +++ b/src/managers/CodeManager.ts @@ -190,11 +190,27 @@ Please briefly explain how the code works in this.` * @protected */ protected async finalizeResponse(): Promise { + console.log('\n') + this.fullResponse += `${this.responseString}\n\n` this.addAssistantResponse(this.responseString) this.isProcessing = false - if (this.responseString !== '') { - const currentNewBlocks = extractCurrentNewBlocks(this.responseString) + if (!this.responseString.includes('======= DONE =======')) { + console.log(colors.yellow('Checking if there is more...')) + this.addUserPrompt( + "If there is more, continue, otherwise print the string '======= DONE ======='.", + ) + const responseStream = await this.gpt.streamText({ + prompt: this.prompt, + messages: this.chatHistory, + }) + + this.handleResponseStream(responseStream) + return + } + + if (this.fullResponse !== '') { + const currentNewBlocks = extractCurrentNewBlocks(this.fullResponse) const [canApply, summary] = await checkBlocksApplicability(currentNewBlocks) if (!canApply) { if (this.retryCount < this.maxRetries) { @@ -216,8 +232,10 @@ Please briefly explain how the code works in this.` this.retryCount = 0 // Reset the retry count on successful application } } + const extraResponse = this.fullResponse + this.fullResponse = '' // Reset the full response - this.handleUserAction(this.responseString) + this.handleUserAction(extraResponse) } } diff --git a/src/managers/DocsManager.ts b/src/managers/DocsManager.ts index 83baa6b..03d33a5 100644 --- a/src/managers/DocsManager.ts +++ b/src/managers/DocsManager.ts @@ -17,8 +17,6 @@ import StreamManager from './StreamManager' * Manages the generation of documentation for specified files. */ class DocsManager extends StreamManager { - private fullDocs = '' - /** * Creates a new DocumentationManager instance. * @param {ClovingGPTOptions} options - Configuration options for the DocumentationManager. @@ -60,7 +58,8 @@ class DocsManager extends StreamManager { * @protected */ protected async finalizeResponse(): Promise { - this.fullDocs += `${this.responseString}\n\n` + console.log('\n') + this.fullResponse += `${this.responseString}\n\n` this.addAssistantResponse(this.responseString) this.isProcessing = false @@ -78,8 +77,8 @@ class DocsManager extends StreamManager { return } - if (this.fullDocs !== '') { - const currentNewBlocks = extractCurrentNewBlocks(this.fullDocs) + if (this.fullResponse !== '') { + const currentNewBlocks = extractCurrentNewBlocks(this.fullResponse) const [canApply, summary] = await checkBlocksApplicability(currentNewBlocks) if (canApply && currentNewBlocks.length > 0) { const shouldSave = await confirm({ diff --git a/src/managers/StreamManager.ts b/src/managers/StreamManager.ts index d54f432..b8b5710 100644 --- a/src/managers/StreamManager.ts +++ b/src/managers/StreamManager.ts @@ -24,6 +24,7 @@ class StreamManager extends EventEmitter { protected gpt: ClovingGPT protected prompt: string = '' protected responseString: string = '' + protected fullResponse: string = '' protected contextFiles: Record = {} protected chatHistory: ChatMessage[] = [] protected chunkManager: ChunkManager