cloving 0.1.21 → 0.1.23

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.
@@ -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
- return `https://generativelanguage.googleapis.com/v1beta/models/${this.model.replace(':', '-')}:generateContent`;
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: false
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: request.stream ?? false
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;