cloving 0.1.21 → 0.1.22
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/claude.js +29 -2
- package/dist/cloving_gpt/adapters/gemini.js +34 -4
- package/dist/cloving_gpt/adapters/mistral.js +45 -2
- package/dist/cloving_gpt/adapters/ollama.js +34 -2
- package/dist/cloving_gpt/adapters/openai.js +46 -2
- package/dist/cloving_gpt/index.js +52 -6
- package/dist/commands/chat.js +14 -0
- package/dist/commands/generate/code.js +8 -316
- package/dist/commands/generate/commit.js +2 -20
- package/dist/commands/proxy.js +11 -0
- package/dist/commands/tokens.js +43 -0
- package/dist/index.js +23 -0
- package/dist/managers/ChatManager.js +283 -0
- package/dist/managers/ChunkManager.js +20 -0
- package/dist/managers/CodeManager.js +319 -0
- package/dist/managers/ProxyManager.js +163 -0
- package/dist/managers/src/managers/ProxyManager.js +1 -0
- package/dist/utils/command_utils.js +1 -1
- package/dist/utils/git_utils.js +21 -1
- package/dist/utils/string_utils.js +21 -2
- package/package.json +4 -1
|
@@ -21,7 +21,7 @@ class ClaudeAdapter {
|
|
|
21
21
|
'anthropic-version': this.anthropicVersion
|
|
22
22
|
};
|
|
23
23
|
}
|
|
24
|
-
getPayload(request) {
|
|
24
|
+
getPayload(request, stream = false) {
|
|
25
25
|
return {
|
|
26
26
|
model: this.model.replace(':', '-'),
|
|
27
27
|
system: 'You are a computer programmer giving advice on how to write better code.',
|
|
@@ -29,7 +29,8 @@ class ClaudeAdapter {
|
|
|
29
29
|
{ role: 'user', content: request.prompt }
|
|
30
30
|
],
|
|
31
31
|
max_tokens: request.maxTokens || 4096,
|
|
32
|
-
temperature: request.temperature || 0.2
|
|
32
|
+
temperature: request.temperature || 0.2,
|
|
33
|
+
stream
|
|
33
34
|
};
|
|
34
35
|
}
|
|
35
36
|
extractResponse(data) {
|
|
@@ -47,6 +48,32 @@ class ClaudeAdapter {
|
|
|
47
48
|
throw error;
|
|
48
49
|
}
|
|
49
50
|
}
|
|
51
|
+
// data example: data: { type: 'content_block_delta', index: 0, delta: { type: 'text_delta', text: 'Hello, how are you?' } }
|
|
52
|
+
convertStream(data) {
|
|
53
|
+
let beginningChar = 0;
|
|
54
|
+
let lastChar = 0;
|
|
55
|
+
while (lastChar < data.length) {
|
|
56
|
+
try {
|
|
57
|
+
let remainingString = data.slice(beginningChar, lastChar);
|
|
58
|
+
// Strip any leading characters until we encounter the first '{' in this block
|
|
59
|
+
const firstBraceIndex = remainingString.indexOf('{');
|
|
60
|
+
if (firstBraceIndex > -1) {
|
|
61
|
+
remainingString = remainingString.slice(firstBraceIndex);
|
|
62
|
+
}
|
|
63
|
+
const parsedObject = JSON.parse(remainingString);
|
|
64
|
+
const output = parsedObject?.delta?.text || '';
|
|
65
|
+
return {
|
|
66
|
+
output,
|
|
67
|
+
lastChar
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
// Incrementally increase the size of the JSON string to parse
|
|
72
|
+
lastChar += 1;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
50
77
|
}
|
|
51
78
|
exports.ClaudeAdapter = ClaudeAdapter;
|
|
52
79
|
ClaudeAdapter.supportedModels = [
|
|
@@ -10,8 +10,13 @@ class GeminiAdapter {
|
|
|
10
10
|
console.log(model);
|
|
11
11
|
});
|
|
12
12
|
}
|
|
13
|
-
getEndpoint() {
|
|
14
|
-
|
|
13
|
+
getEndpoint(stream = false) {
|
|
14
|
+
if (stream) {
|
|
15
|
+
return `https://generativelanguage.googleapis.com/v1beta/models/${this.model.replace(':', '-')}:streamGenerateContent`;
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
return `https://generativelanguage.googleapis.com/v1beta/models/${this.model.replace(':', '-')}:generateContent`;
|
|
19
|
+
}
|
|
15
20
|
}
|
|
16
21
|
getHeaders(apiKey) {
|
|
17
22
|
return {
|
|
@@ -19,7 +24,7 @@ class GeminiAdapter {
|
|
|
19
24
|
'x-goog-api-key': apiKey
|
|
20
25
|
};
|
|
21
26
|
}
|
|
22
|
-
getPayload(request) {
|
|
27
|
+
getPayload(request, stream = false) {
|
|
23
28
|
return {
|
|
24
29
|
contents: [
|
|
25
30
|
{
|
|
@@ -31,7 +36,7 @@ class GeminiAdapter {
|
|
|
31
36
|
}
|
|
32
37
|
],
|
|
33
38
|
generationConfig: {
|
|
34
|
-
temperature: 0.2,
|
|
39
|
+
temperature: request.temperature || 0.2,
|
|
35
40
|
topK: 40,
|
|
36
41
|
topP: 0.95,
|
|
37
42
|
maxOutputTokens: 1024
|
|
@@ -53,6 +58,31 @@ class GeminiAdapter {
|
|
|
53
58
|
throw error;
|
|
54
59
|
}
|
|
55
60
|
}
|
|
61
|
+
convertStream(data) {
|
|
62
|
+
let beginningChar = 0;
|
|
63
|
+
let lastChar = 0;
|
|
64
|
+
while (lastChar < data.length) {
|
|
65
|
+
try {
|
|
66
|
+
let remainingString = data.slice(beginningChar, lastChar);
|
|
67
|
+
// Strip any leading characters until we encounter the first '{' in this block
|
|
68
|
+
const firstBraceIndex = remainingString.indexOf('{');
|
|
69
|
+
if (firstBraceIndex > -1) {
|
|
70
|
+
remainingString = remainingString.slice(firstBraceIndex);
|
|
71
|
+
}
|
|
72
|
+
const parsedObject = JSON.parse(remainingString);
|
|
73
|
+
const output = parsedObject?.candidates[0]?.content?.parts[0]?.text || '';
|
|
74
|
+
return {
|
|
75
|
+
output,
|
|
76
|
+
lastChar
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
// Incrementally increase the size of the JSON string to parse
|
|
81
|
+
lastChar += 1;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
56
86
|
}
|
|
57
87
|
exports.GeminiAdapter = GeminiAdapter;
|
|
58
88
|
GeminiAdapter.supportedModels = [
|
|
@@ -19,18 +19,61 @@ class MistralAdapter {
|
|
|
19
19
|
'Content-Type': 'application/json'
|
|
20
20
|
};
|
|
21
21
|
}
|
|
22
|
-
getPayload(request) {
|
|
22
|
+
getPayload(request, stream = false) {
|
|
23
23
|
return {
|
|
24
24
|
model: this.model.replace(':', '-'),
|
|
25
25
|
messages: [{ role: "user", content: request.prompt }],
|
|
26
26
|
max_tokens: request.maxTokens,
|
|
27
27
|
temperature: request.temperature || 0.2,
|
|
28
|
-
stream
|
|
28
|
+
stream
|
|
29
29
|
};
|
|
30
30
|
}
|
|
31
31
|
extractResponse(data) {
|
|
32
32
|
return data.choices[0].message.content;
|
|
33
33
|
}
|
|
34
|
+
// data example:
|
|
35
|
+
// {
|
|
36
|
+
// id: 'chatcmpl-9tL477A98d54qvVQqJT010bm8BLJl',
|
|
37
|
+
// object: 'chat.completion.chunk',
|
|
38
|
+
// created: 1722976043,
|
|
39
|
+
// model: 'gpt-4o-2024-05-13',
|
|
40
|
+
// system_fingerprint: 'fp_3aa7262c27',
|
|
41
|
+
// choices: [
|
|
42
|
+
// {
|
|
43
|
+
// "index": 0,
|
|
44
|
+
// "delta": {
|
|
45
|
+
// "content": " basic"
|
|
46
|
+
// },
|
|
47
|
+
// "logprobs": null,
|
|
48
|
+
// "finish_reason": null
|
|
49
|
+
// }
|
|
50
|
+
// ]
|
|
51
|
+
// }
|
|
52
|
+
convertStream(data) {
|
|
53
|
+
let beginningChar = 0;
|
|
54
|
+
let lastChar = 0;
|
|
55
|
+
while (lastChar < data.length) {
|
|
56
|
+
try {
|
|
57
|
+
let remainingString = data.slice(beginningChar, lastChar);
|
|
58
|
+
// Strip any leading characters until we encounter the first '{' in this block
|
|
59
|
+
const firstBraceIndex = remainingString.indexOf('{');
|
|
60
|
+
if (firstBraceIndex > -1) {
|
|
61
|
+
remainingString = remainingString.slice(firstBraceIndex);
|
|
62
|
+
}
|
|
63
|
+
const parsedObject = JSON.parse(remainingString);
|
|
64
|
+
const output = parsedObject?.choices[0]?.delta?.content || '';
|
|
65
|
+
return {
|
|
66
|
+
output,
|
|
67
|
+
lastChar
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
// Incrementally increase the size of the JSON string to parse
|
|
72
|
+
lastChar += 1;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
34
77
|
}
|
|
35
78
|
exports.MistralAdapter = MistralAdapter;
|
|
36
79
|
MistralAdapter.supportedModels = [
|
|
@@ -40,11 +40,11 @@ class OllamaAdapter {
|
|
|
40
40
|
'Content-Type': 'application/json'
|
|
41
41
|
};
|
|
42
42
|
}
|
|
43
|
-
getPayload(request) {
|
|
43
|
+
getPayload(request, stream = false) {
|
|
44
44
|
return {
|
|
45
45
|
model: this.model,
|
|
46
46
|
prompt: request.prompt,
|
|
47
|
-
stream
|
|
47
|
+
stream
|
|
48
48
|
};
|
|
49
49
|
}
|
|
50
50
|
extractResponse(data) {
|
|
@@ -62,6 +62,38 @@ class OllamaAdapter {
|
|
|
62
62
|
throw error;
|
|
63
63
|
}
|
|
64
64
|
}
|
|
65
|
+
// data example:
|
|
66
|
+
// {
|
|
67
|
+
// model: 'dolphin-llama3:latest',
|
|
68
|
+
// created_at: '2024-08-06T21:04:34.616355Z',
|
|
69
|
+
// response: 'The',
|
|
70
|
+
// done: false
|
|
71
|
+
// }
|
|
72
|
+
convertStream(data) {
|
|
73
|
+
let beginningChar = 0;
|
|
74
|
+
let lastChar = 0;
|
|
75
|
+
while (lastChar < data.length) {
|
|
76
|
+
try {
|
|
77
|
+
let remainingString = data.slice(beginningChar, lastChar);
|
|
78
|
+
// Strip any leading characters until we encounter the first '{' in this block
|
|
79
|
+
const firstBraceIndex = remainingString.indexOf('{');
|
|
80
|
+
if (firstBraceIndex > -1) {
|
|
81
|
+
remainingString = remainingString.slice(firstBraceIndex);
|
|
82
|
+
}
|
|
83
|
+
const parsedObject = JSON.parse(remainingString);
|
|
84
|
+
const output = parsedObject?.response || '';
|
|
85
|
+
return {
|
|
86
|
+
output,
|
|
87
|
+
lastChar
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
catch (error) {
|
|
91
|
+
// Incrementally increase the size of the JSON string to parse
|
|
92
|
+
lastChar += 1;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
65
97
|
}
|
|
66
98
|
exports.OllamaAdapter = OllamaAdapter;
|
|
67
99
|
OllamaAdapter.supportedModels = [];
|
|
@@ -19,17 +19,61 @@ class OpenAIAdapter {
|
|
|
19
19
|
'Content-Type': 'application/json'
|
|
20
20
|
};
|
|
21
21
|
}
|
|
22
|
-
getPayload(request) {
|
|
22
|
+
getPayload(request, stream = false) {
|
|
23
23
|
return {
|
|
24
24
|
model: this.model.replace(':', '-'),
|
|
25
25
|
messages: [{ role: "user", content: request.prompt }],
|
|
26
26
|
max_tokens: request.maxTokens,
|
|
27
|
-
temperature: request.temperature || 0.2
|
|
27
|
+
temperature: request.temperature || 0.2,
|
|
28
|
+
stream
|
|
28
29
|
};
|
|
29
30
|
}
|
|
30
31
|
extractResponse(data) {
|
|
31
32
|
return data.choices[0].message.content;
|
|
32
33
|
}
|
|
34
|
+
// data example:
|
|
35
|
+
// {
|
|
36
|
+
// id: 'chatcmpl-9tL477A98d54qvVQqJT010bm8BLJl',
|
|
37
|
+
// object: 'chat.completion.chunk',
|
|
38
|
+
// created: 1722976043,
|
|
39
|
+
// model: 'gpt-4o-2024-05-13',
|
|
40
|
+
// system_fingerprint: 'fp_3aa7262c27',
|
|
41
|
+
// choices: [
|
|
42
|
+
// {
|
|
43
|
+
// "index": 0,
|
|
44
|
+
// "delta": {
|
|
45
|
+
// "content": " basic"
|
|
46
|
+
// },
|
|
47
|
+
// "logprobs": null,
|
|
48
|
+
// "finish_reason": null
|
|
49
|
+
// }
|
|
50
|
+
// ]
|
|
51
|
+
// }
|
|
52
|
+
convertStream(data) {
|
|
53
|
+
let beginningChar = 0;
|
|
54
|
+
let lastChar = 0;
|
|
55
|
+
while (lastChar < data.length) {
|
|
56
|
+
try {
|
|
57
|
+
let remainingString = data.slice(beginningChar, lastChar);
|
|
58
|
+
// Strip any leading characters until we encounter the first '{' in this block
|
|
59
|
+
const firstBraceIndex = remainingString.indexOf('{');
|
|
60
|
+
if (firstBraceIndex > -1) {
|
|
61
|
+
remainingString = remainingString.slice(firstBraceIndex);
|
|
62
|
+
}
|
|
63
|
+
const parsedObject = JSON.parse(remainingString);
|
|
64
|
+
const output = parsedObject?.choices[0]?.delta?.content || '';
|
|
65
|
+
return {
|
|
66
|
+
output,
|
|
67
|
+
lastChar
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
// Incrementally increase the size of the JSON string to parse
|
|
72
|
+
lastChar += 1;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
33
77
|
}
|
|
34
78
|
exports.OpenAIAdapter = OpenAIAdapter;
|
|
35
79
|
OpenAIAdapter.supportedModels = [
|
|
@@ -3,6 +3,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const fs_1 = __importDefault(require("fs"));
|
|
7
|
+
const os_1 = __importDefault(require("os"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
6
9
|
const axios_1 = __importDefault(require("axios"));
|
|
7
10
|
const child_process_1 = require("child_process");
|
|
8
11
|
const process_1 = __importDefault(require("process"));
|
|
@@ -13,9 +16,6 @@ const mistral_1 = require("./adapters/mistral");
|
|
|
13
16
|
const ollama_1 = require("./adapters/ollama");
|
|
14
17
|
const gemini_1 = require("./adapters/gemini");
|
|
15
18
|
const config_utils_1 = require("../utils/config_utils");
|
|
16
|
-
const fs_1 = __importDefault(require("fs"));
|
|
17
|
-
const os_1 = __importDefault(require("os"));
|
|
18
|
-
const path_1 = __importDefault(require("path"));
|
|
19
19
|
class ClovingGPT {
|
|
20
20
|
constructor(options) {
|
|
21
21
|
const { model: partialModel } = options;
|
|
@@ -33,6 +33,8 @@ class ClovingGPT {
|
|
|
33
33
|
this.apiKey = modelConfig.apiKey;
|
|
34
34
|
this.temperature = options.temperature || modelConfig.temperature || 0.2;
|
|
35
35
|
this.silent = options.silent || modelConfig.silent;
|
|
36
|
+
this.stream = options.stream || false;
|
|
37
|
+
this.timeout = options.timeout || 60000; // Default timeout of 60 seconds
|
|
36
38
|
switch (provider) {
|
|
37
39
|
case 'claude':
|
|
38
40
|
this.adapter = new claude_1.ClaudeAdapter(model);
|
|
@@ -92,10 +94,51 @@ class ClovingGPT {
|
|
|
92
94
|
}
|
|
93
95
|
return prompt;
|
|
94
96
|
}
|
|
97
|
+
async streamText(request) {
|
|
98
|
+
request.stream = true;
|
|
99
|
+
request.temperature || (request.temperature = this.temperature);
|
|
100
|
+
const endpoint = this.adapter.getEndpoint(this.stream);
|
|
101
|
+
const payload = this.adapter.getPayload(request, this.stream);
|
|
102
|
+
const headers = this.adapter.getHeaders(this.apiKey);
|
|
103
|
+
const reviewedPrompt = await this.reviewPrompt(request.prompt, endpoint);
|
|
104
|
+
if (reviewedPrompt === null) {
|
|
105
|
+
throw new Error('Operation cancelled by user');
|
|
106
|
+
}
|
|
107
|
+
request.prompt = reviewedPrompt;
|
|
108
|
+
const maxRetries = 5;
|
|
109
|
+
let attempt = 0;
|
|
110
|
+
let delay = 1000; // Initial delay of 1 second
|
|
111
|
+
while (attempt < maxRetries) {
|
|
112
|
+
try {
|
|
113
|
+
return await (0, axios_1.default)({
|
|
114
|
+
method: 'post',
|
|
115
|
+
url: endpoint,
|
|
116
|
+
data: payload,
|
|
117
|
+
headers: headers,
|
|
118
|
+
responseType: 'stream',
|
|
119
|
+
timeout: this.timeout
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
catch (err) {
|
|
123
|
+
const error = err;
|
|
124
|
+
if (error.response && error.response.status === 429) {
|
|
125
|
+
attempt++;
|
|
126
|
+
const tokenCount = payload.messages.reduce((acc, message) => acc + Math.ceil(message.content.length / 4), 0).toLocaleString();
|
|
127
|
+
console.warn(`Rate limit error for this ${tokenCount} token prompt. Possibly past the token limit for this AI API. Try including fewer code files. Retrying in ${delay / 1000} seconds... (Attempt ${attempt} of ${maxRetries})`);
|
|
128
|
+
await new Promise(resolve => setTimeout(resolve, delay));
|
|
129
|
+
delay *= 2; // Exponential backoff
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
throw error;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
throw new Error('Max retries exceeded');
|
|
137
|
+
}
|
|
95
138
|
async generateText(request) {
|
|
96
139
|
request.temperature || (request.temperature = this.temperature);
|
|
97
|
-
const endpoint = this.adapter.getEndpoint();
|
|
98
|
-
const payload = this.adapter.getPayload(request);
|
|
140
|
+
const endpoint = this.adapter.getEndpoint(this.stream);
|
|
141
|
+
const payload = this.adapter.getPayload(request, this.stream);
|
|
99
142
|
const headers = this.adapter.getHeaders(this.apiKey);
|
|
100
143
|
const reviewedPrompt = await this.reviewPrompt(request.prompt, endpoint);
|
|
101
144
|
if (reviewedPrompt === null) {
|
|
@@ -111,9 +154,12 @@ class ClovingGPT {
|
|
|
111
154
|
if (errorMessage === '') {
|
|
112
155
|
errorMessage = 'connection error';
|
|
113
156
|
}
|
|
114
|
-
console.error(`Error communicating with the GPT server (${this.adapter.getEndpoint()}):`, errorMessage);
|
|
157
|
+
console.error(`Error communicating with the GPT server (${this.adapter.getEndpoint(this.stream)}):`, errorMessage);
|
|
115
158
|
throw error;
|
|
116
159
|
}
|
|
117
160
|
}
|
|
161
|
+
convertStream(data) {
|
|
162
|
+
return this.adapter.convertStream(data);
|
|
163
|
+
}
|
|
118
164
|
}
|
|
119
165
|
exports.default = ClovingGPT;
|
|
@@ -0,0 +1,14 @@
|
|
|
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 ChatManager_1 = __importDefault(require("../managers/ChatManager"));
|
|
7
|
+
const config_utils_1 = require("../utils/config_utils");
|
|
8
|
+
const chat = async (options) => {
|
|
9
|
+
options.silent = (0, config_utils_1.getConfig)(options).globalSilent || false;
|
|
10
|
+
options.stream = true;
|
|
11
|
+
const chatManager = new ChatManager_1.default(options);
|
|
12
|
+
await chatManager.initialize();
|
|
13
|
+
};
|
|
14
|
+
exports.default = chat;
|