cloving 0.3.9 → 0.3.11
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/cloving_gpt/adapters/azureopenai.js +69 -0
- package/dist/cloving_gpt/adapters/claude.js +39 -1
- package/dist/cloving_gpt/adapters/gemini.js +37 -0
- package/dist/cloving_gpt/adapters/mistral.js +37 -0
- package/dist/cloving_gpt/adapters/ollama.js +36 -7
- package/dist/cloving_gpt/adapters/openai.js +9 -0
- package/dist/cloving_gpt/index.js +24 -5
- package/dist/commands/config.js +59 -1
- package/dist/commands/generate/documentation.js +11 -0
- package/dist/commands/models.js +2 -0
- package/dist/index.js +10 -0
- package/dist/managers/DocumentationManager.js +113 -0
- package/dist/package.json +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AzureOpenAIAdapter = void 0;
|
|
4
|
+
class AzureOpenAIAdapter {
|
|
5
|
+
static listSupportedModels() {
|
|
6
|
+
AzureOpenAIAdapter.supportedModels.forEach((model) => {
|
|
7
|
+
console.log(model);
|
|
8
|
+
});
|
|
9
|
+
}
|
|
10
|
+
constructor(model, endpoint) {
|
|
11
|
+
this.model = model;
|
|
12
|
+
this.endpoint = endpoint;
|
|
13
|
+
}
|
|
14
|
+
getEndpoint() {
|
|
15
|
+
return this.endpoint;
|
|
16
|
+
}
|
|
17
|
+
getHeaders(apiKey) {
|
|
18
|
+
return {
|
|
19
|
+
Authorization: `Bearer ${apiKey}`,
|
|
20
|
+
'Content-Type': 'application/json',
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
getPayload(request, stream = false) {
|
|
24
|
+
return {
|
|
25
|
+
model: this.model.replace('azureopenai:', '').replace(':', '-'),
|
|
26
|
+
messages: request.messages && request.messages.length > 0
|
|
27
|
+
? request.messages
|
|
28
|
+
: [{ role: 'user', content: request.prompt }],
|
|
29
|
+
max_tokens: request.maxTokens,
|
|
30
|
+
temperature: request.temperature || 0.2,
|
|
31
|
+
stream,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
extractResponse(data) {
|
|
35
|
+
return data.choices[0].message.content;
|
|
36
|
+
}
|
|
37
|
+
convertStream(data) {
|
|
38
|
+
let beginningChar = 0;
|
|
39
|
+
let lastChar = 0;
|
|
40
|
+
while (lastChar < data.length) {
|
|
41
|
+
try {
|
|
42
|
+
let remainingString = data.slice(beginningChar, lastChar);
|
|
43
|
+
const firstBraceIndex = remainingString.indexOf('{');
|
|
44
|
+
if (firstBraceIndex > -1) {
|
|
45
|
+
remainingString = remainingString.slice(firstBraceIndex);
|
|
46
|
+
}
|
|
47
|
+
const parsedObject = JSON.parse(remainingString);
|
|
48
|
+
const output = parsedObject?.choices[0]?.delta?.content || '';
|
|
49
|
+
return {
|
|
50
|
+
output,
|
|
51
|
+
lastChar,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
catch (error) {
|
|
55
|
+
lastChar += 1;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
exports.AzureOpenAIAdapter = AzureOpenAIAdapter;
|
|
62
|
+
AzureOpenAIAdapter.supportedModels = [
|
|
63
|
+
'azureopenai:gpt:4o-2024-08-06',
|
|
64
|
+
'azureopenai:gpt:4o',
|
|
65
|
+
'azureopenai:gpt:4o-mini',
|
|
66
|
+
'azureopenai:gpt:4-turbo',
|
|
67
|
+
'azureopenai:gpt:3.5-turbo',
|
|
68
|
+
// Add more supported models as needed
|
|
69
|
+
];
|
|
@@ -1,19 +1,38 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.ClaudeAdapter = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* ClaudeAdapter class implements the Adapter interface for Claude AI models.
|
|
6
|
+
*/
|
|
4
7
|
class ClaudeAdapter {
|
|
8
|
+
/**
|
|
9
|
+
* Initializes a new ClaudeAdapter instance.
|
|
10
|
+
* @param model - The Claude model identifier.
|
|
11
|
+
*/
|
|
5
12
|
constructor(model) {
|
|
6
13
|
this.model = model;
|
|
7
14
|
this.anthropicVersion = '2023-06-01';
|
|
8
15
|
}
|
|
16
|
+
/**
|
|
17
|
+
* Logs all supported Claude models to the console.
|
|
18
|
+
*/
|
|
9
19
|
static listSupportedModels() {
|
|
10
20
|
ClaudeAdapter.supportedModels.forEach((model) => {
|
|
11
21
|
console.log(model);
|
|
12
22
|
});
|
|
13
23
|
}
|
|
24
|
+
/**
|
|
25
|
+
* Returns the API endpoint for Claude.
|
|
26
|
+
* @returns The API endpoint URL.
|
|
27
|
+
*/
|
|
14
28
|
getEndpoint() {
|
|
15
29
|
return `https://api.anthropic.com/v1/messages`;
|
|
16
30
|
}
|
|
31
|
+
/**
|
|
32
|
+
* Generates headers for API requests.
|
|
33
|
+
* @param apiKey - The API key for authentication.
|
|
34
|
+
* @returns An object containing the required headers.
|
|
35
|
+
*/
|
|
17
36
|
getHeaders(apiKey) {
|
|
18
37
|
return {
|
|
19
38
|
'x-api-key': apiKey,
|
|
@@ -21,6 +40,12 @@ class ClaudeAdapter {
|
|
|
21
40
|
'anthropic-version': this.anthropicVersion,
|
|
22
41
|
};
|
|
23
42
|
}
|
|
43
|
+
/**
|
|
44
|
+
* Prepares the payload for API requests.
|
|
45
|
+
* @param request - The GPTRequest object containing request details.
|
|
46
|
+
* @param stream - Whether to enable streaming (default: false).
|
|
47
|
+
* @returns An object containing the prepared payload.
|
|
48
|
+
*/
|
|
24
49
|
getPayload(request, stream = false) {
|
|
25
50
|
let system = 'You are a computer programmer giving advice on how to write better code.';
|
|
26
51
|
if (request.messages && request.messages.length > 0 && request.messages[0].role === 'system') {
|
|
@@ -38,6 +63,12 @@ class ClaudeAdapter {
|
|
|
38
63
|
stream,
|
|
39
64
|
};
|
|
40
65
|
}
|
|
66
|
+
/**
|
|
67
|
+
* Extracts the response text from the API response data.
|
|
68
|
+
* @param data - The API response data.
|
|
69
|
+
* @returns The extracted response text.
|
|
70
|
+
* @throws Error if the response structure is invalid.
|
|
71
|
+
*/
|
|
41
72
|
extractResponse(data) {
|
|
42
73
|
try {
|
|
43
74
|
if (data && data.content && Array.isArray(data.content) && data.content.length > 0) {
|
|
@@ -53,7 +84,11 @@ class ClaudeAdapter {
|
|
|
53
84
|
throw error;
|
|
54
85
|
}
|
|
55
86
|
}
|
|
56
|
-
|
|
87
|
+
/**
|
|
88
|
+
* Converts streaming data to OpenAIStreamChunk format.
|
|
89
|
+
* @param data - The streaming data string.
|
|
90
|
+
* @returns An OpenAIStreamChunk object or null if parsing fails.
|
|
91
|
+
*/
|
|
57
92
|
convertStream(data) {
|
|
58
93
|
let beginningChar = 0;
|
|
59
94
|
let lastChar = 0;
|
|
@@ -81,6 +116,9 @@ class ClaudeAdapter {
|
|
|
81
116
|
}
|
|
82
117
|
}
|
|
83
118
|
exports.ClaudeAdapter = ClaudeAdapter;
|
|
119
|
+
/**
|
|
120
|
+
* Array of supported Claude model identifiers.
|
|
121
|
+
*/
|
|
84
122
|
ClaudeAdapter.supportedModels = [
|
|
85
123
|
'claude:claude-3-5:sonnet-20240620',
|
|
86
124
|
'claude:claude-3:opus-20240229',
|
|
@@ -1,15 +1,30 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.GeminiAdapter = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* GeminiAdapter class implements the Adapter interface for Google's Gemini AI model.
|
|
6
|
+
*/
|
|
4
7
|
class GeminiAdapter {
|
|
8
|
+
/**
|
|
9
|
+
* Creates a new GeminiAdapter instance.
|
|
10
|
+
* @param model - The Gemini model to use.
|
|
11
|
+
*/
|
|
5
12
|
constructor(model) {
|
|
6
13
|
this.model = model;
|
|
7
14
|
}
|
|
15
|
+
/**
|
|
16
|
+
* Lists all supported Gemini models to the console.
|
|
17
|
+
*/
|
|
8
18
|
static async listSupportedModels() {
|
|
9
19
|
GeminiAdapter.supportedModels.forEach((model) => {
|
|
10
20
|
console.log(model);
|
|
11
21
|
});
|
|
12
22
|
}
|
|
23
|
+
/**
|
|
24
|
+
* Gets the appropriate API endpoint URL based on whether streaming is required.
|
|
25
|
+
* @param stream - Whether to use streaming endpoint.
|
|
26
|
+
* @returns The API endpoint URL.
|
|
27
|
+
*/
|
|
13
28
|
getEndpoint(stream = false) {
|
|
14
29
|
if (stream) {
|
|
15
30
|
return `https://generativelanguage.googleapis.com/v1beta/models/${this.model.replace(':', '-')}:streamGenerateContent`;
|
|
@@ -18,12 +33,23 @@ class GeminiAdapter {
|
|
|
18
33
|
return `https://generativelanguage.googleapis.com/v1beta/models/${this.model.replace(':', '-')}:generateContent`;
|
|
19
34
|
}
|
|
20
35
|
}
|
|
36
|
+
/**
|
|
37
|
+
* Generates headers for the API request.
|
|
38
|
+
* @param apiKey - The API key for authentication.
|
|
39
|
+
* @returns An object containing the necessary headers.
|
|
40
|
+
*/
|
|
21
41
|
getHeaders(apiKey) {
|
|
22
42
|
return {
|
|
23
43
|
'Content-Type': 'application/json',
|
|
24
44
|
'x-goog-api-key': apiKey,
|
|
25
45
|
};
|
|
26
46
|
}
|
|
47
|
+
/**
|
|
48
|
+
* Prepares the payload for the API request.
|
|
49
|
+
* @param request - The GPTRequest object containing prompt and other parameters.
|
|
50
|
+
* @param stream - Whether the request is for streaming.
|
|
51
|
+
* @returns The formatted payload object.
|
|
52
|
+
*/
|
|
27
53
|
getPayload(request, stream = false) {
|
|
28
54
|
return {
|
|
29
55
|
contents: [
|
|
@@ -44,6 +70,12 @@ class GeminiAdapter {
|
|
|
44
70
|
},
|
|
45
71
|
};
|
|
46
72
|
}
|
|
73
|
+
/**
|
|
74
|
+
* Extracts the response text from the API response data.
|
|
75
|
+
* @param data - The raw API response data.
|
|
76
|
+
* @returns The extracted response text.
|
|
77
|
+
* @throws Error if the response structure is invalid.
|
|
78
|
+
*/
|
|
47
79
|
extractResponse(data) {
|
|
48
80
|
try {
|
|
49
81
|
if (data &&
|
|
@@ -64,6 +96,11 @@ class GeminiAdapter {
|
|
|
64
96
|
throw error;
|
|
65
97
|
}
|
|
66
98
|
}
|
|
99
|
+
/**
|
|
100
|
+
* Converts a stream chunk to an OpenAIStreamChunk format.
|
|
101
|
+
* @param data - The raw stream chunk data.
|
|
102
|
+
* @returns An OpenAIStreamChunk object or null if parsing fails.
|
|
103
|
+
*/
|
|
67
104
|
convertStream(data) {
|
|
68
105
|
let beginningChar = 0;
|
|
69
106
|
let lastChar = 0;
|
|
@@ -1,24 +1,48 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.MistralAdapter = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* MistralAdapter class
|
|
6
|
+
* Implements the Adapter interface for Mistral AI models.
|
|
7
|
+
*/
|
|
4
8
|
class MistralAdapter {
|
|
9
|
+
/**
|
|
10
|
+
* Prints all supported models to the console
|
|
11
|
+
*/
|
|
5
12
|
static listSupportedModels() {
|
|
6
13
|
MistralAdapter.supportedModels.forEach((model) => {
|
|
7
14
|
console.log(model);
|
|
8
15
|
});
|
|
9
16
|
}
|
|
17
|
+
/**
|
|
18
|
+
* Constructor
|
|
19
|
+
* @param model - The Mistral AI model to use
|
|
20
|
+
*/
|
|
10
21
|
constructor(model) {
|
|
11
22
|
this.model = model;
|
|
12
23
|
}
|
|
24
|
+
/**
|
|
25
|
+
* @returns The Mistral AI API endpoint
|
|
26
|
+
*/
|
|
13
27
|
getEndpoint() {
|
|
14
28
|
return 'https://api.mistral.ai/v1/chat/completions';
|
|
15
29
|
}
|
|
30
|
+
/**
|
|
31
|
+
* @param apiKey - The API key for authentication
|
|
32
|
+
* @returns Headers for the API request
|
|
33
|
+
*/
|
|
16
34
|
getHeaders(apiKey) {
|
|
17
35
|
return {
|
|
18
36
|
Authorization: `Bearer ${apiKey}`,
|
|
19
37
|
'Content-Type': 'application/json',
|
|
20
38
|
};
|
|
21
39
|
}
|
|
40
|
+
/**
|
|
41
|
+
* Prepares the payload for the API request
|
|
42
|
+
* @param request - The GPT request object
|
|
43
|
+
* @param stream - Whether to use streaming mode
|
|
44
|
+
* @returns The formatted payload
|
|
45
|
+
*/
|
|
22
46
|
getPayload(request, stream = false) {
|
|
23
47
|
return {
|
|
24
48
|
model: this.model.replace(':', '-'),
|
|
@@ -30,6 +54,11 @@ class MistralAdapter {
|
|
|
30
54
|
stream,
|
|
31
55
|
};
|
|
32
56
|
}
|
|
57
|
+
/**
|
|
58
|
+
* Extracts the response content from the API data
|
|
59
|
+
* @param data - The API response data
|
|
60
|
+
* @returns The extracted response content
|
|
61
|
+
*/
|
|
33
62
|
extractResponse(data) {
|
|
34
63
|
return data.choices[0].message.content;
|
|
35
64
|
}
|
|
@@ -51,6 +80,11 @@ class MistralAdapter {
|
|
|
51
80
|
// }
|
|
52
81
|
// ]
|
|
53
82
|
// }
|
|
83
|
+
/**
|
|
84
|
+
* Converts streaming data to OpenAIStreamChunk format
|
|
85
|
+
* @param data - The streaming data string
|
|
86
|
+
* @returns Parsed OpenAIStreamChunk or null if parsing fails
|
|
87
|
+
*/
|
|
54
88
|
convertStream(data) {
|
|
55
89
|
let beginningChar = 0;
|
|
56
90
|
let lastChar = 0;
|
|
@@ -78,6 +112,9 @@ class MistralAdapter {
|
|
|
78
112
|
}
|
|
79
113
|
}
|
|
80
114
|
exports.MistralAdapter = MistralAdapter;
|
|
115
|
+
/**
|
|
116
|
+
* List of supported Mistral AI models
|
|
117
|
+
*/
|
|
81
118
|
MistralAdapter.supportedModels = [
|
|
82
119
|
'mistral:mistral:embed',
|
|
83
120
|
'mistral:mistral:tiny-latest',
|
|
@@ -5,10 +5,20 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.OllamaAdapter = void 0;
|
|
7
7
|
const axios_1 = __importDefault(require("axios"));
|
|
8
|
+
/**
|
|
9
|
+
* Adapter for interacting with the Ollama API.
|
|
10
|
+
*/
|
|
8
11
|
class OllamaAdapter {
|
|
12
|
+
/**
|
|
13
|
+
* Constructor to initialize the OllamaAdapter with a specific model.
|
|
14
|
+
* @param model - The model to be used by the adapter.
|
|
15
|
+
*/
|
|
9
16
|
constructor(model) {
|
|
10
17
|
this.model = model;
|
|
11
18
|
}
|
|
19
|
+
/**
|
|
20
|
+
* Fetches and lists supported models from the Ollama API.
|
|
21
|
+
*/
|
|
12
22
|
static async listSupportedModels() {
|
|
13
23
|
try {
|
|
14
24
|
const endpoint = 'http://localhost:11434/api/tags';
|
|
@@ -31,15 +41,30 @@ class OllamaAdapter {
|
|
|
31
41
|
// do nothing, no ollama server running
|
|
32
42
|
}
|
|
33
43
|
}
|
|
44
|
+
/**
|
|
45
|
+
* Returns the endpoint URL for generating responses.
|
|
46
|
+
* @returns The endpoint URL as a string.
|
|
47
|
+
*/
|
|
34
48
|
getEndpoint() {
|
|
35
49
|
return `http://localhost:11434/api/generate`;
|
|
36
50
|
}
|
|
51
|
+
/**
|
|
52
|
+
* Returns the headers required for making API requests.
|
|
53
|
+
* @param apiKey - The API key for authorization.
|
|
54
|
+
* @returns An object containing the headers.
|
|
55
|
+
*/
|
|
37
56
|
getHeaders(apiKey) {
|
|
38
57
|
return {
|
|
39
58
|
Authorization: `Bearer ${apiKey}`,
|
|
40
59
|
'Content-Type': 'application/json',
|
|
41
60
|
};
|
|
42
61
|
}
|
|
62
|
+
/**
|
|
63
|
+
* Constructs the payload for the API request.
|
|
64
|
+
* @param request - The GPT request object containing the prompt.
|
|
65
|
+
* @param stream - Boolean indicating if the response should be streamed.
|
|
66
|
+
* @returns An object containing the payload.
|
|
67
|
+
*/
|
|
43
68
|
getPayload(request, stream = false) {
|
|
44
69
|
return {
|
|
45
70
|
model: this.model,
|
|
@@ -47,6 +72,12 @@ class OllamaAdapter {
|
|
|
47
72
|
stream,
|
|
48
73
|
};
|
|
49
74
|
}
|
|
75
|
+
/**
|
|
76
|
+
* Extracts the response from the API response data.
|
|
77
|
+
* @param data - The response data from the API.
|
|
78
|
+
* @returns The extracted response as a string.
|
|
79
|
+
* @throws Will throw an error if the response structure is invalid.
|
|
80
|
+
*/
|
|
50
81
|
extractResponse(data) {
|
|
51
82
|
try {
|
|
52
83
|
if (data && typeof data === 'object' && 'response' in data) {
|
|
@@ -62,13 +93,11 @@ class OllamaAdapter {
|
|
|
62
93
|
throw error;
|
|
63
94
|
}
|
|
64
95
|
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
// done: false
|
|
71
|
-
// }
|
|
96
|
+
/**
|
|
97
|
+
* Converts a stream of data into an OpenAIStreamChunk.
|
|
98
|
+
* @param data - The string data to be converted.
|
|
99
|
+
* @returns An OpenAIStreamChunk object or null if conversion fails.
|
|
100
|
+
*/
|
|
72
101
|
convertStream(data) {
|
|
73
102
|
let beginningChar = 0;
|
|
74
103
|
let lastChar = 0;
|
|
@@ -1,24 +1,30 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.OpenAIAdapter = void 0;
|
|
4
|
+
// OpenAIAdapter class implements the Adapter interface
|
|
4
5
|
class OpenAIAdapter {
|
|
6
|
+
// Method to list supported models
|
|
5
7
|
static listSupportedModels() {
|
|
6
8
|
OpenAIAdapter.supportedModels.forEach((model) => {
|
|
7
9
|
console.log(model);
|
|
8
10
|
});
|
|
9
11
|
}
|
|
12
|
+
// Constructor to initialize the model
|
|
10
13
|
constructor(model) {
|
|
11
14
|
this.model = model;
|
|
12
15
|
}
|
|
16
|
+
// Method to get the API endpoint
|
|
13
17
|
getEndpoint() {
|
|
14
18
|
return `https://api.openai.com/v1/chat/completions`;
|
|
15
19
|
}
|
|
20
|
+
// Method to get the headers for the API request
|
|
16
21
|
getHeaders(apiKey) {
|
|
17
22
|
return {
|
|
18
23
|
Authorization: `Bearer ${apiKey}`,
|
|
19
24
|
'Content-Type': 'application/json',
|
|
20
25
|
};
|
|
21
26
|
}
|
|
27
|
+
// Method to get the payload for the API request
|
|
22
28
|
getPayload(request, stream = false) {
|
|
23
29
|
return {
|
|
24
30
|
model: this.model.replace(':', '-'),
|
|
@@ -30,9 +36,11 @@ class OpenAIAdapter {
|
|
|
30
36
|
stream,
|
|
31
37
|
};
|
|
32
38
|
}
|
|
39
|
+
// Method to extract the response from the API response data
|
|
33
40
|
extractResponse(data) {
|
|
34
41
|
return data.choices[0].message.content;
|
|
35
42
|
}
|
|
43
|
+
// Method to convert the stream data into OpenAIStreamChunk format
|
|
36
44
|
// data example:
|
|
37
45
|
// {
|
|
38
46
|
// id: 'chatcmpl-9tL477A98d54qvVQqJT010bm8BLJl',
|
|
@@ -78,6 +86,7 @@ class OpenAIAdapter {
|
|
|
78
86
|
}
|
|
79
87
|
}
|
|
80
88
|
exports.OpenAIAdapter = OpenAIAdapter;
|
|
89
|
+
// List of supported models
|
|
81
90
|
OpenAIAdapter.supportedModels = [
|
|
82
91
|
'openai:gpt:4o-2024-08-06',
|
|
83
92
|
'openai:gpt:4o',
|
|
@@ -16,6 +16,7 @@ const openai_1 = require("./adapters/openai");
|
|
|
16
16
|
const mistral_1 = require("./adapters/mistral");
|
|
17
17
|
const ollama_1 = require("./adapters/ollama");
|
|
18
18
|
const gemini_1 = require("./adapters/gemini");
|
|
19
|
+
const azureopenai_1 = require("./adapters/azureopenai");
|
|
19
20
|
const config_utils_1 = require("../utils/config_utils");
|
|
20
21
|
class ClovingGPT {
|
|
21
22
|
constructor(options) {
|
|
@@ -52,6 +53,12 @@ class ClovingGPT {
|
|
|
52
53
|
case 'gemini':
|
|
53
54
|
this.adapter = new gemini_1.GeminiAdapter(model);
|
|
54
55
|
break;
|
|
56
|
+
case 'azureopenai':
|
|
57
|
+
if (!modelConfig.endpoint) {
|
|
58
|
+
throw new Error('Azure OpenAI endpoint not configured');
|
|
59
|
+
}
|
|
60
|
+
this.adapter = new azureopenai_1.AzureOpenAIAdapter(model, modelConfig.endpoint);
|
|
61
|
+
break;
|
|
55
62
|
default:
|
|
56
63
|
throw new Error(`Unsupported provider: ${provider}`);
|
|
57
64
|
}
|
|
@@ -165,12 +172,24 @@ class ClovingGPT {
|
|
|
165
172
|
}
|
|
166
173
|
catch (err) {
|
|
167
174
|
const error = err;
|
|
168
|
-
let errorMessage = error
|
|
169
|
-
if (
|
|
170
|
-
|
|
175
|
+
let errorMessage = 'An error occurred while communicating with the AI server';
|
|
176
|
+
if (error.response) {
|
|
177
|
+
// The request was made and the server responded with a status code
|
|
178
|
+
// that falls out of the range of 2xx
|
|
179
|
+
errorMessage = `Server responded with status ${error.response.status}: ${error.response.statusText}`;
|
|
180
|
+
}
|
|
181
|
+
else if (error.request) {
|
|
182
|
+
// The request was made but no response was received
|
|
183
|
+
errorMessage = 'No response received from the server';
|
|
184
|
+
}
|
|
185
|
+
else {
|
|
186
|
+
// Something happened in setting up the request that triggered an Error
|
|
187
|
+
errorMessage = error.message || 'Unknown error occurred';
|
|
171
188
|
}
|
|
172
|
-
console.error(
|
|
173
|
-
|
|
189
|
+
console.error(`${colors_1.default.red.bold('ERROR')} ${errorMessage}\n` +
|
|
190
|
+
`Endpoint: ${this.adapter.getEndpoint(this.stream)}\n` +
|
|
191
|
+
`Details: ${colors_1.default.yellow(JSON.stringify(error.response?.data || {}, null, 2))}\n`);
|
|
192
|
+
throw new Error(errorMessage);
|
|
174
193
|
}
|
|
175
194
|
}
|
|
176
195
|
convertStream(data) {
|
package/dist/commands/config.js
CHANGED
|
@@ -3,7 +3,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.config = void 0;
|
|
4
4
|
const config_utils_1 = require("../utils/config_utils");
|
|
5
5
|
const prompt_utils_1 = require("../utils/prompt_utils");
|
|
6
|
+
// Add this type definition at the top of the file
|
|
6
7
|
const prompts_1 = require("@inquirer/prompts");
|
|
8
|
+
/**
|
|
9
|
+
* Configures the AI models by prompting the user for various settings.
|
|
10
|
+
*
|
|
11
|
+
* @returns {Promise<void>} A promise that resolves when the configuration is complete.
|
|
12
|
+
*/
|
|
7
13
|
const config = async () => {
|
|
8
14
|
let currentConfig = (0, config_utils_1.getConfig)({});
|
|
9
15
|
// Ensure models are initialized properly
|
|
@@ -18,23 +24,35 @@ const config = async () => {
|
|
|
18
24
|
let continueConfig = true;
|
|
19
25
|
while (continueConfig) {
|
|
20
26
|
const providers = [...new Set(models.map((model) => model.split(':')[0]))];
|
|
27
|
+
/**
|
|
28
|
+
* Prompts the user to select a provider from the available models.
|
|
29
|
+
*/
|
|
21
30
|
const selectedProvider = await (0, prompts_1.select)({
|
|
22
31
|
message: 'Select a provider:',
|
|
23
32
|
choices: providers.map((provider) => ({ name: provider, value: provider })),
|
|
24
33
|
});
|
|
25
34
|
const providerModels = models.filter((model) => model.startsWith(selectedProvider));
|
|
26
35
|
const modelCategories = [...new Set(providerModels.map((model) => model.split(':')[1]))];
|
|
36
|
+
/**
|
|
37
|
+
* Prompts the user to select a category from the selected provider's models.
|
|
38
|
+
*/
|
|
27
39
|
const selectedCategory = await (0, prompts_1.select)({
|
|
28
40
|
message: 'Select a category:',
|
|
29
41
|
choices: modelCategories.map((category) => ({ name: category, value: category })),
|
|
30
42
|
});
|
|
31
43
|
const specificModels = providerModels.filter((model) => model.split(':')[1] === selectedCategory);
|
|
44
|
+
/**
|
|
45
|
+
* Prompts the user to select a specific model from the selected category.
|
|
46
|
+
*/
|
|
32
47
|
const modelIndex = await (0, prompts_1.select)({
|
|
33
48
|
message: "Select an AI model you'd like to use:",
|
|
34
49
|
choices: specificModels.map((model, index) => ({ name: model, value: index })),
|
|
35
50
|
pageSize: specificModels.length,
|
|
36
51
|
});
|
|
37
52
|
const selectedModel = specificModels[modelIndex];
|
|
53
|
+
/**
|
|
54
|
+
* Prompts the user to enter the API key for the selected model.
|
|
55
|
+
*/
|
|
38
56
|
const apiKey = await (0, prompts_1.input)({
|
|
39
57
|
message: `Enter your API key for ${selectedModel}: `,
|
|
40
58
|
});
|
|
@@ -43,10 +61,18 @@ const config = async () => {
|
|
|
43
61
|
if (!currentConfig.models[provider]) {
|
|
44
62
|
currentConfig.models[provider] = {};
|
|
45
63
|
}
|
|
64
|
+
/**
|
|
65
|
+
* Prompts the user to set the selected model as the primary model.
|
|
66
|
+
*/
|
|
46
67
|
const primary = await (0, prompts_1.confirm)({
|
|
47
68
|
message: 'Set this model as the primary? Primary models are used by default if your prompt fits within its context window. You can configure backup models for larger prompts.',
|
|
48
69
|
default: true,
|
|
49
70
|
});
|
|
71
|
+
/**
|
|
72
|
+
* Prompts the user to enter the priority for the selected model.
|
|
73
|
+
*
|
|
74
|
+
* @returns {string} The priority value as a string.
|
|
75
|
+
*/
|
|
50
76
|
const priority = await (0, prompts_1.input)({
|
|
51
77
|
message: 'Enter the priority for this model (0-100). Higher priority AI APIs are chosen as long as the prompt fits its context window:',
|
|
52
78
|
default: primary ? '100' : '0',
|
|
@@ -58,14 +84,25 @@ const config = async () => {
|
|
|
58
84
|
return true;
|
|
59
85
|
},
|
|
60
86
|
});
|
|
87
|
+
/**
|
|
88
|
+
* Prompts the user to decide if they want to review all prompts before they are sent to the selected model.
|
|
89
|
+
*/
|
|
61
90
|
const review = await (0, prompts_1.confirm)({
|
|
62
91
|
message: `Do you want to review all prompts before they are sent to ${selectedModel}?`,
|
|
63
92
|
default: true,
|
|
64
93
|
});
|
|
94
|
+
/**
|
|
95
|
+
* Prompts the user to decide if they trust the selected model with sensitive information.
|
|
96
|
+
*/
|
|
65
97
|
const trust = await (0, prompts_1.confirm)({
|
|
66
98
|
message: `Do you trust ${selectedModel} with sensitive information?`,
|
|
67
99
|
default: false,
|
|
68
100
|
});
|
|
101
|
+
/**
|
|
102
|
+
* Prompts the user to enter the temperature setting for the selected model.
|
|
103
|
+
*
|
|
104
|
+
* @returns {string} The temperature value as a string.
|
|
105
|
+
*/
|
|
69
106
|
const temperature = await (0, prompts_1.input)({
|
|
70
107
|
message: `Enter the temperature for ${selectedModel} (0.0 - 1.0): [0.2]`,
|
|
71
108
|
default: '0.2',
|
|
@@ -78,7 +115,10 @@ const config = async () => {
|
|
|
78
115
|
},
|
|
79
116
|
});
|
|
80
117
|
const parsedTemperature = parseFloat(temperature);
|
|
81
|
-
|
|
118
|
+
/**
|
|
119
|
+
* Constructs the model configuration object.
|
|
120
|
+
*/
|
|
121
|
+
let modelConfig = {
|
|
82
122
|
apiKey,
|
|
83
123
|
primary,
|
|
84
124
|
priority: parseInt(priority, 10),
|
|
@@ -86,6 +126,21 @@ const config = async () => {
|
|
|
86
126
|
trust,
|
|
87
127
|
temperature: parsedTemperature,
|
|
88
128
|
};
|
|
129
|
+
if (provider === 'azureopenai') {
|
|
130
|
+
/**
|
|
131
|
+
* Prompts the user to enter the Azure OpenAI endpoint URL.
|
|
132
|
+
*/
|
|
133
|
+
const endpoint = await (0, prompts_1.input)({
|
|
134
|
+
message: 'Enter the Azure OpenAI endpoint URL:',
|
|
135
|
+
validate: (value) => {
|
|
136
|
+
if (!value.startsWith('https://')) {
|
|
137
|
+
return 'Please enter a valid HTTPS URL';
|
|
138
|
+
}
|
|
139
|
+
return true;
|
|
140
|
+
},
|
|
141
|
+
});
|
|
142
|
+
modelConfig.endpoint = endpoint;
|
|
143
|
+
}
|
|
89
144
|
currentConfig.models[provider][model] = modelConfig;
|
|
90
145
|
if (primary) {
|
|
91
146
|
// Ensure only one primary model
|
|
@@ -97,6 +152,9 @@ const config = async () => {
|
|
|
97
152
|
}
|
|
98
153
|
}
|
|
99
154
|
}
|
|
155
|
+
/**
|
|
156
|
+
* Prompts the user to decide if they want to configure another model.
|
|
157
|
+
*/
|
|
100
158
|
const anotherModel = await (0, prompts_1.confirm)({
|
|
101
159
|
message: 'Do you want to configure another model?',
|
|
102
160
|
default: true,
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const DocumentationManager_1 = __importDefault(require("../../managers/DocumentationManager"));
|
|
7
|
+
const documentation = async (options) => {
|
|
8
|
+
const documentationManager = new DocumentationManager_1.default(options);
|
|
9
|
+
await documentationManager.generateDocumentation();
|
|
10
|
+
};
|
|
11
|
+
exports.default = documentation;
|
package/dist/commands/models.js
CHANGED
|
@@ -5,6 +5,7 @@ const openai_1 = require("../cloving_gpt/adapters/openai");
|
|
|
5
5
|
const ollama_1 = require("../cloving_gpt/adapters/ollama");
|
|
6
6
|
const gemini_1 = require("../cloving_gpt/adapters/gemini");
|
|
7
7
|
const mistral_1 = require("../cloving_gpt/adapters/mistral");
|
|
8
|
+
const azureopenai_1 = require("../cloving_gpt/adapters/azureopenai");
|
|
8
9
|
const listModels = async () => {
|
|
9
10
|
claude_1.ClaudeAdapter.listSupportedModels();
|
|
10
11
|
gemini_1.GeminiAdapter.listSupportedModels();
|
|
@@ -16,5 +17,6 @@ const listModels = async () => {
|
|
|
16
17
|
// do nothing, no ollama server running
|
|
17
18
|
}
|
|
18
19
|
openai_1.OpenAIAdapter.listSupportedModels();
|
|
20
|
+
azureopenai_1.AzureOpenAIAdapter.listSupportedModels();
|
|
19
21
|
};
|
|
20
22
|
exports.default = listModels;
|
package/dist/index.js
CHANGED
|
@@ -17,6 +17,7 @@ const commit_1 = __importDefault(require("./commands/generate/commit"));
|
|
|
17
17
|
const context_1 = __importDefault(require("./commands/generate/context"));
|
|
18
18
|
const unit_tests_1 = __importDefault(require("./commands/generate/unit_tests"));
|
|
19
19
|
const review_1 = __importDefault(require("./commands/generate/review"));
|
|
20
|
+
const documentation_1 = __importDefault(require("./commands/generate/documentation"));
|
|
20
21
|
const prompt_utils_1 = require("./utils/prompt_utils");
|
|
21
22
|
const program = new commander_1.Command();
|
|
22
23
|
program
|
|
@@ -121,4 +122,13 @@ generate
|
|
|
121
122
|
.option('-m, --model <model>', 'Select the model to use (e.g., openai, claude, ollama, ollama:llama3, claude:claude-3-5-sonnet-20240620)')
|
|
122
123
|
.option('-t, --temperature <temperature>', 'Temperature for the model (default 0.2)')
|
|
123
124
|
.action(review_1.default);
|
|
125
|
+
generate
|
|
126
|
+
.command('documentation')
|
|
127
|
+
.alias('d')
|
|
128
|
+
.description('Generate documentation for the project')
|
|
129
|
+
.option('-s, --silent', 'Run the command without asking for confirmation of submitting prompts')
|
|
130
|
+
.option('-f, --files <filenames...>', 'Specify filenames for files you want to document')
|
|
131
|
+
.option('-m, --model <model>', 'Select the model to use (e.g., openai, claude, ollama, ollama:llama3, claude:claude-3-5-sonnet-20240620)')
|
|
132
|
+
.option('-t, --temperature <temperature>', 'Temperature for the model (default 0.2)')
|
|
133
|
+
.action(documentation_1.default);
|
|
124
134
|
program.parse(process.argv);
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const prompts_1 = require("@inquirer/prompts");
|
|
7
|
+
const colors_1 = __importDefault(require("colors"));
|
|
8
|
+
const cli_highlight_1 = __importDefault(require("cli-highlight"));
|
|
9
|
+
const cloving_gpt_1 = __importDefault(require("../cloving_gpt"));
|
|
10
|
+
const config_utils_1 = require("../utils/config_utils");
|
|
11
|
+
const prompt_utils_1 = require("../utils/prompt_utils");
|
|
12
|
+
const string_utils_1 = require("../utils/string_utils");
|
|
13
|
+
/**
|
|
14
|
+
* Manages the generation of documentation for specified files.
|
|
15
|
+
*/
|
|
16
|
+
class DocumentationManager {
|
|
17
|
+
/**
|
|
18
|
+
* Creates a new DocumentationManager instance.
|
|
19
|
+
* @param {ClovingGPTOptions} options - Configuration options for the DocumentationManager.
|
|
20
|
+
*/
|
|
21
|
+
constructor(options) {
|
|
22
|
+
this.options = options;
|
|
23
|
+
this.contextFiles = {};
|
|
24
|
+
this.chatHistory = [];
|
|
25
|
+
this.options.silent = (0, config_utils_1.getConfig)(options).globalSilent || false;
|
|
26
|
+
this.gpt = new cloving_gpt_1.default(options);
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Generates documentation for the specified files.
|
|
30
|
+
* @returns {Promise<void>}
|
|
31
|
+
*/
|
|
32
|
+
async generateDocumentation() {
|
|
33
|
+
try {
|
|
34
|
+
await this.loadContextFiles();
|
|
35
|
+
if (this.chatHistory.length === 0) {
|
|
36
|
+
this.chatHistory.push({ role: 'user', content: prompt_utils_1.CODEGEN_INSTRUCTIONS });
|
|
37
|
+
this.chatHistory.push({ role: 'assistant', content: 'What would you like to do?' });
|
|
38
|
+
}
|
|
39
|
+
const prompt = this.generateDocumentationPrompt();
|
|
40
|
+
this.chatHistory.push({ role: 'user', content: prompt });
|
|
41
|
+
const response = await this.gpt.generateText({ prompt, messages: this.chatHistory });
|
|
42
|
+
this.displayGeneratedDocumentation(response);
|
|
43
|
+
const currentNewBlocks = (0, string_utils_1.extractCurrentNewBlocks)(response);
|
|
44
|
+
if (currentNewBlocks.length > 0) {
|
|
45
|
+
const shouldSave = await (0, prompts_1.confirm)({
|
|
46
|
+
message: 'Do you want to save the generated documentation?',
|
|
47
|
+
default: true,
|
|
48
|
+
});
|
|
49
|
+
if (shouldSave) {
|
|
50
|
+
await (0, string_utils_1.applyAndSaveCurrentNewBlocks)(currentNewBlocks);
|
|
51
|
+
console.log(colors_1.default.green('\nDocumentation has been saved to the respective files.'));
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
console.error(colors_1.default.red('Error generating documentation:'), error);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Displays the generated documentation in the console with syntax highlighting.
|
|
61
|
+
* @param {string} rawDocumentationResponse - The raw documentation response from the GPT model.
|
|
62
|
+
*/
|
|
63
|
+
displayGeneratedDocumentation(rawDocumentationResponse) {
|
|
64
|
+
(0, string_utils_1.parseMarkdownInstructions)(rawDocumentationResponse).map((code) => {
|
|
65
|
+
if (code.trim().startsWith('```')) {
|
|
66
|
+
const lines = code.split('\n');
|
|
67
|
+
const language = code.match(/```(\w+)/)?.[1] || 'plaintext';
|
|
68
|
+
console.log(lines[0]);
|
|
69
|
+
try {
|
|
70
|
+
console.log((0, cli_highlight_1.default)(lines.slice(1, -1).join('\n'), { language }));
|
|
71
|
+
}
|
|
72
|
+
catch (error) {
|
|
73
|
+
// don't highlight if it fails
|
|
74
|
+
console.log(lines.slice(1, -1).join('\n'));
|
|
75
|
+
}
|
|
76
|
+
console.log(lines.slice(-1)[0]);
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
console.log((0, cli_highlight_1.default)(code, { language: 'markdown' }));
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Loads the context files specified in the options.
|
|
85
|
+
* @returns {Promise<void>}
|
|
86
|
+
*/
|
|
87
|
+
async loadContextFiles() {
|
|
88
|
+
if (this.options.files) {
|
|
89
|
+
for (const file of this.options.files) {
|
|
90
|
+
this.contextFiles = await (0, prompt_utils_1.addFileOrDirectoryToContext)(file, this.contextFiles, this.options);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
console.log(colors_1.default.yellow('No files specified. Please provide files using the -f option.'));
|
|
95
|
+
process.exit(1);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Generates the documentation prompt to be sent to the GPT model.
|
|
100
|
+
* @returns {string} The generated documentation prompt.
|
|
101
|
+
*/
|
|
102
|
+
generateDocumentationPrompt() {
|
|
103
|
+
const contextFileContents = Object.entries(this.contextFiles)
|
|
104
|
+
.map(([file, content]) => `### File: ${file}\n\n\`\`\`\n${content}\n\`\`\`\n`)
|
|
105
|
+
.join('\n\n');
|
|
106
|
+
return `Please generate documentation for the following files. Add or update documentation comments for functions, classes, and modules as appropriate. Use the standard documentation format for the respective language (e.g., JSDoc for JavaScript/TypeScript, docstrings for Python, etc.).
|
|
107
|
+
|
|
108
|
+
${contextFileContents}
|
|
109
|
+
|
|
110
|
+
Please provide the updated files with added documentation using the CURRENT/NEW block format. Only include the parts of the files that have changed.`;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
exports.default = DocumentationManager;
|
package/dist/package.json
CHANGED