@gitsense/gsc-utils 0.2.0 → 0.2.2
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/dist/gsc-utils.cjs.js +352 -37
- package/dist/gsc-utils.esm.js +352 -37
- package/package.json +1 -1
- package/src/AnalyzerUtils/constants.js +17 -0
- package/src/AnalyzerUtils/contextMapper.js +51 -0
- package/src/AnalyzerUtils/dataValidator.js +81 -0
- package/src/AnalyzerUtils/index.js +21 -0
- package/src/AnalyzerUtils/responseProcessor.js +131 -0
- package/src/ChatUtils.js +11 -2
- package/src/GitSenseChatUtils.js +6 -0
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Component: AnalyzerUtils Data Validator
|
|
3
|
+
* Block-UUID: 1317cc51-fca0-49b7-9e4b-b3e1a06ab93f
|
|
4
|
+
* Parent-UUID: N/A
|
|
5
|
+
* Version: 1.0.0
|
|
6
|
+
* Description: Validates extracted analysis data against chat context and expected schema.
|
|
7
|
+
* Language: JavaScript
|
|
8
|
+
* Created-at: 2025-08-28T15:56:40.319Z
|
|
9
|
+
* Authors: Gemini 2.5 Flash (v1.0.0)
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
const AnalysisBlockUtils = require('../AnalysisBlockUtils');
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Validates the extracted analysis blocks and their metadata.
|
|
17
|
+
* Checks for valid chat IDs/paths and uses AnalysisBlockUtils for further metadata validation.
|
|
18
|
+
* This function is adapted from the original `analysisValidation.js` in `gsc-conversation-view`.
|
|
19
|
+
*
|
|
20
|
+
* @param {Array<Object>} analysisBlocks - Array of extracted analysis code blocks (Markdown overviews).
|
|
21
|
+
* @param {Array<Object|null>} analysisMetadataBlocks - Array of extracted analysis metadata blocks (JSON).
|
|
22
|
+
* @param {Map<number, string>} chatIdToPathMap - Map of chat IDs to file paths from context messages.
|
|
23
|
+
* @returns {{validAnalysisData: Array<Object>, invalidAnalysisBlocks: Array<string|Object>}}
|
|
24
|
+
* An object containing arrays of valid analysis data and invalid analysis blocks.
|
|
25
|
+
*/
|
|
26
|
+
function validateLLMAnalysisData(analysisBlocks, analysisMetadataBlocks, chatIdToPathMap) {
|
|
27
|
+
const validAnalysisData = []; // Store data for the "Save All" button
|
|
28
|
+
const invalidAnalysisBlocks = []; // Store invalid analysis blocks
|
|
29
|
+
|
|
30
|
+
analysisBlocks.forEach((block, index) => {
|
|
31
|
+
// Ensure metadata is parsed from the block's content for initial checks
|
|
32
|
+
const overviewMetadata = AnalysisBlockUtils.parseOverviewMetadata(block.content);
|
|
33
|
+
const metadataBlock = analysisMetadataBlocks[index];
|
|
34
|
+
const isDone = metadataBlock ? true : false; // Check if metadata block was successfully processed
|
|
35
|
+
|
|
36
|
+
// Skip if metadata block is missing (still streaming or error)
|
|
37
|
+
if (!overviewMetadata || !isDone) {
|
|
38
|
+
// If metadata block is missing but streaming stopped, it's an error handled in responseProcessor
|
|
39
|
+
// If overviewMetadata is missing, it's an error handled in responseProcessor
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const chatId = overviewMetadata['Chat ID'];
|
|
44
|
+
const path = overviewMetadata['Path'];
|
|
45
|
+
|
|
46
|
+
// Is this a valid chat id and path id? Some LLMs will actually hallucinate this
|
|
47
|
+
if (!chatId || !path || !chatIdToPathMap.has(chatId)) {
|
|
48
|
+
invalidAnalysisBlocks.push(`<li>#${chatId || 'N/A'} => ${path || 'N/A'} (Invalid Chat ID or Path)</li>`);
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Perform detailed metadata validation using AnalysisBlockUtils
|
|
53
|
+
const validation = AnalysisBlockUtils.validateAnalysisMetadata(overviewMetadata);
|
|
54
|
+
|
|
55
|
+
if (validation.isValid) {
|
|
56
|
+
// Prepare data for API call (map keys if necessary)
|
|
57
|
+
const analysisData = {
|
|
58
|
+
chatId: overviewMetadata['Chat ID'],
|
|
59
|
+
// The original analyzeHandler used 'Message ID', 'Repository', 'Summarized At', 'Analyze At',
|
|
60
|
+
// 'Summary', 'Key Functionality', 'Keywords' from overviewMetadata.
|
|
61
|
+
// For batch processing, we primarily need chatId, content, and the full JSON metadata.
|
|
62
|
+
// The other fields can be derived from the full JSON metadata if needed.
|
|
63
|
+
path: overviewMetadata['Path'],
|
|
64
|
+
content: block.content, // The full Markdown overview
|
|
65
|
+
type: AnalysisBlockUtils.getAnalysisBlockType(block.content), // e.g., 'tiny-overview::file-content::default'
|
|
66
|
+
// We know metadataBlock.content is a valid JSON from responseProcessor
|
|
67
|
+
metadata: JSON.parse(metadataBlock.content) // The full JSON metadata object
|
|
68
|
+
};
|
|
69
|
+
validAnalysisData.push(analysisData); // Add to list for saving
|
|
70
|
+
} else {
|
|
71
|
+
// Add invalid analysis block with validation details
|
|
72
|
+
invalidAnalysisBlocks.push({ block, validation });
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
return { validAnalysisData, invalidAnalysisBlocks };
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
module.exports = {
|
|
80
|
+
validateLLMAnalysisData
|
|
81
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Component: AnalyzerUtils Index
|
|
3
|
+
* Block-UUID: b403b6a1-230b-4247-8cd6-2a3d068f4bbf
|
|
4
|
+
* Parent-UUID: N/A
|
|
5
|
+
* Version: 1.0.0
|
|
6
|
+
* Description: Aggregates and exports all utility functions from the AnalyzerUtils module.
|
|
7
|
+
* Language: JavaScript
|
|
8
|
+
* Created-at: 2025-08-28T15:56:40.319Z
|
|
9
|
+
* Authors: Gemini 2.5 Flash (v1.0.0)
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
const { buildChatIdToPathMap } = require('./contextMapper');
|
|
14
|
+
const { processLLMAnalysisResponse } = require('./responseProcessor');
|
|
15
|
+
const { validateLLMAnalysisData } = require('./dataValidator');
|
|
16
|
+
|
|
17
|
+
module.exports = {
|
|
18
|
+
buildChatIdToPathMap,
|
|
19
|
+
processLLMAnalysisResponse,
|
|
20
|
+
validateLLMAnalysisData
|
|
21
|
+
};
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Component: AnalyzerUtils Response Processor
|
|
3
|
+
* Block-UUID: 2a3b4c5d-6e7f-4a8b-9c0d-1e2f3a4b5c6d
|
|
4
|
+
* Parent-UUID: N/A
|
|
5
|
+
* Version: 1.0.0
|
|
6
|
+
* Description: Extracts and performs initial validation of analysis and metadata code blocks from raw LLM message content.
|
|
7
|
+
* Language: JavaScript
|
|
8
|
+
* Created-at: 2025-08-28T15:56:40.319Z
|
|
9
|
+
* Authors: Gemini 2.5 Flash (v1.0.0)
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
const CodeBlockUtils = require('../CodeBlockUtils');
|
|
14
|
+
const AnalysisBlockUtils = require('../AnalysisBlockUtils');
|
|
15
|
+
const GSToolBlockUtils = require('../GSToolBlockUtils');
|
|
16
|
+
const JsonUtils = require('../JsonUtils');
|
|
17
|
+
const { ANALYZE_HEADER_PREFIX } = require('./constants');
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Extracts code blocks from the message content, identifies analysis and metadata blocks,
|
|
21
|
+
* and performs initial validation (block type, metadata presence, JSON format).
|
|
22
|
+
* This function is adapted from the original `blockProcessing.js` in `gsc-conversation-view`.
|
|
23
|
+
*
|
|
24
|
+
* @param {string} messageContent - The full content of the message.
|
|
25
|
+
* @param {boolean} stoppedStreaming - Flag indicating if the message streaming has stopped.
|
|
26
|
+
* @returns {{analysisBlocks: Array<Object>, analysisMetadataBlocks: Array<Object|null>, error: string|null}}
|
|
27
|
+
* An object containing the extracted blocks and any processing error.
|
|
28
|
+
*/
|
|
29
|
+
function processLLMAnalysisResponse(messageContent, stoppedStreaming) {
|
|
30
|
+
const silent = { silent: true };
|
|
31
|
+
const { blocks, warnings } = CodeBlockUtils.extractCodeBlocks(messageContent, silent);
|
|
32
|
+
|
|
33
|
+
const analysisBlocks = [];
|
|
34
|
+
const analysisMetadataBlocks = [];
|
|
35
|
+
let error = null;
|
|
36
|
+
|
|
37
|
+
for (let i = 0; i < blocks.length; i += 2) {
|
|
38
|
+
const analysisBlock = blocks[i];
|
|
39
|
+
|
|
40
|
+
// Make sure this is an analysis block by checking its content
|
|
41
|
+
if (!analysisBlock.content.trimStart().startsWith(ANALYZE_HEADER_PREFIX)) {
|
|
42
|
+
// Also check if it's a GitSense Tool Block, which should be ignored by this analyzer
|
|
43
|
+
if (GSToolBlockUtils.isToolBlock(analysisBlock.content)) {
|
|
44
|
+
// If it's a tool block, it's not an analysis block, so skip it and don't treat as error
|
|
45
|
+
// Adjust index to skip this block and its potential "metadata" if it was paired
|
|
46
|
+
if (blocks[i+1] && blocks[i+1].language === 'json') {
|
|
47
|
+
i += 1; // Skip the next block too if it's a JSON block (likely tool config)
|
|
48
|
+
}
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (stoppedStreaming) {
|
|
53
|
+
error = `Analysis block #${i} does not start with the "${ANALYZE_HEADER_PREFIX}" header.`;
|
|
54
|
+
}
|
|
55
|
+
// If we are still streaming, we may not have enough information to tell what type
|
|
56
|
+
// of block this is, so stop looking
|
|
57
|
+
break;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Add the analysis block (Markdown overview)
|
|
61
|
+
analysisBlocks.push(analysisBlock);
|
|
62
|
+
|
|
63
|
+
// Make sure there is an analysis metadata block (JSON)
|
|
64
|
+
const analysisMetadataBlock = blocks[i + 1];
|
|
65
|
+
|
|
66
|
+
if (!analysisMetadataBlock) {
|
|
67
|
+
if (stoppedStreaming) {
|
|
68
|
+
error = `No analysis metadata found for analysis block (index ${i}).`;
|
|
69
|
+
} else {
|
|
70
|
+
// Add a null metadata block to let use know we are still streaming
|
|
71
|
+
analysisMetadataBlocks.push(null);
|
|
72
|
+
}
|
|
73
|
+
break;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// We found a code block but we don't know if it is valid or not
|
|
77
|
+
// 1. First make sure the code block is a JSON type
|
|
78
|
+
// 2. Try to parse the JSON
|
|
79
|
+
if (analysisMetadataBlock.language !== 'json') {
|
|
80
|
+
if (stoppedStreaming) {
|
|
81
|
+
error = `Analysis metadata block for "${analysisBlock.overviewMetadata?.Path || 'Unknown Path'}" has invalid language "${analysisMetadataBlock.language}". Expected "json".`;
|
|
82
|
+
} else {
|
|
83
|
+
// Add a null metadata block to let use know we are still streaming
|
|
84
|
+
analysisMetadataBlocks.push(null);
|
|
85
|
+
}
|
|
86
|
+
break;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
try {
|
|
90
|
+
// Check for comments within JSON, which would make it invalid for direct parsing
|
|
91
|
+
const comments = JsonUtils.detectJsonComments(analysisMetadataBlock.content);
|
|
92
|
+
if (comments.length > 0) {
|
|
93
|
+
error = `The analysis metadata block for "${analysisBlock.overviewMetadata?.Path || 'Unknown Path'}" contains comments, which makes it invalid JSON.`;
|
|
94
|
+
if (stoppedStreaming || blocks[i + 2]) { // If streaming stopped or not the last block
|
|
95
|
+
break;
|
|
96
|
+
} else {
|
|
97
|
+
analysisMetadataBlocks.push(null); // Add null to keep arrays aligned
|
|
98
|
+
return { analysisBlocks, analysisMetadataBlocks, error: null };
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
JSON.parse(analysisMetadataBlock.content.trim());
|
|
103
|
+
analysisMetadataBlocks.push(analysisMetadataBlock);
|
|
104
|
+
} catch (err) {
|
|
105
|
+
const path = analysisBlock.overviewMetadata?.Path || 'Unknown Path';
|
|
106
|
+
error = `The analysis metadata block for "${path}" contains an invalid JSON: ${err.message}`;
|
|
107
|
+
|
|
108
|
+
// If streaming has stopped or if this is not the last block, set error and break.
|
|
109
|
+
// Remember to increment by two since every second block is the meta block.
|
|
110
|
+
if (stoppedStreaming || blocks[i + 2]) {
|
|
111
|
+
break;
|
|
112
|
+
} else {
|
|
113
|
+
// Do nothing since the error is most certaintly due to the fact that we are still
|
|
114
|
+
// streaming the JSON
|
|
115
|
+
analysisMetadataBlocks.push(null); // Add null to keep arrays aligned
|
|
116
|
+
return { analysisBlocks, analysisMetadataBlocks, error: null };
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// If streaming stopped and no overview blocks were found, set an error
|
|
122
|
+
if (stoppedStreaming && analysisBlocks.length === 0) {
|
|
123
|
+
error = 'Analysis stopped without producing any data.';
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return { analysisBlocks, analysisMetadataBlocks, error };
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
module.exports = {
|
|
130
|
+
processLLMAnalysisResponse
|
|
131
|
+
};
|
package/src/ChatUtils.js
CHANGED
|
@@ -62,13 +62,21 @@ function isNewAnalyzerChat(chat, model) {
|
|
|
62
62
|
/**
|
|
63
63
|
* Determines if the current chat session appears to be an "Analyze" session.
|
|
64
64
|
* @param {object} chat - The chat object.
|
|
65
|
-
* @param {string} model - Optional model.
|
|
66
65
|
* @returns {boolean} True if the chat matches the Overview Builder pattern, false otherwise.
|
|
67
66
|
*/
|
|
68
|
-
function isAnalyzeChat(chat
|
|
67
|
+
function isAnalyzeChat(chat) {
|
|
69
68
|
return chat.type === 'analyze';
|
|
70
69
|
}
|
|
71
70
|
|
|
71
|
+
/**
|
|
72
|
+
* Determines if the current chat session appears to be an "Analyze Builder" session.
|
|
73
|
+
* @param {object} chat - The chat object.
|
|
74
|
+
* @returns {boolean} True if the chat matches the Overview Builder pattern, false otherwise.
|
|
75
|
+
*/
|
|
76
|
+
function isAnalyzeBuilderChat(chat) {
|
|
77
|
+
return chat.type === 'analyze-builder';
|
|
78
|
+
}
|
|
79
|
+
|
|
72
80
|
/**
|
|
73
81
|
* Determines if the current chat session appears to be an "Ask" session.
|
|
74
82
|
* @param {object} chat - The chat object.
|
|
@@ -120,6 +128,7 @@ module.exports = {
|
|
|
120
128
|
isAskChat,
|
|
121
129
|
isNewAnalyzerChat,
|
|
122
130
|
isAnalyzeChat,
|
|
131
|
+
isAnalyzeBuilderChat,
|
|
123
132
|
isPlanChat,
|
|
124
133
|
isCodeChat,
|
|
125
134
|
getChatMessages
|
package/src/GitSenseChatUtils.js
CHANGED
|
@@ -15,6 +15,7 @@ const CodeBlockUtils = require('./CodeBlockUtils');
|
|
|
15
15
|
const ContextUtils = require('./ContextUtils');
|
|
16
16
|
const MessageUtils = require('./MessageUtils');
|
|
17
17
|
const AnalysisBlockUtils = require('./AnalysisBlockUtils');
|
|
18
|
+
const AnalyzerUtils = require('./AnalyzerUtils');
|
|
18
19
|
const PatchUtils = require('./PatchUtils');
|
|
19
20
|
const GSToolBlockUtils = require('./GSToolBlockUtils');
|
|
20
21
|
const LLMUtils = require('./LLMUtils');
|
|
@@ -360,6 +361,11 @@ module.exports = {
|
|
|
360
361
|
parseOverviewMetadata,
|
|
361
362
|
validateOverviewMetadata,
|
|
362
363
|
|
|
364
|
+
// Analyzer Utilities
|
|
365
|
+
buildChatIdToPathMap: AnalyzerUtils.buildChatIdToPathMap,
|
|
366
|
+
processLLMAnalysisResponse: AnalyzerUtils.processLLMAnalysisResponse,
|
|
367
|
+
validateLLMAnalysisData: AnalyzerUtils.validateLLMAnalysisData,
|
|
368
|
+
|
|
363
369
|
// ChatUtils
|
|
364
370
|
getChatMessages,
|
|
365
371
|
|