@entro314labs/ai-changelog-generator 3.1.1 → 3.2.0
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/CHANGELOG.md +383 -877
- package/README.md +8 -3
- package/ai-changelog-mcp.sh +0 -0
- package/ai-changelog.sh +0 -0
- package/bin/ai-changelog-dxt.js +9 -9
- package/bin/ai-changelog-mcp.js +19 -17
- package/bin/ai-changelog.js +6 -6
- package/package.json +80 -48
- package/src/ai-changelog-generator.js +83 -81
- package/src/application/orchestrators/changelog.orchestrator.js +791 -516
- package/src/application/services/application.service.js +137 -128
- package/src/cli.js +76 -57
- package/src/domains/ai/ai-analysis.service.js +289 -209
- package/src/domains/analysis/analysis.engine.js +253 -193
- package/src/domains/changelog/changelog.service.js +1062 -784
- package/src/domains/changelog/workspace-changelog.service.js +420 -249
- package/src/domains/git/git-repository.analyzer.js +348 -258
- package/src/domains/git/git.service.js +132 -112
- package/src/infrastructure/cli/cli.controller.js +390 -274
- package/src/infrastructure/config/configuration.manager.js +220 -190
- package/src/infrastructure/interactive/interactive-staging.service.js +154 -135
- package/src/infrastructure/interactive/interactive-workflow.service.js +200 -159
- package/src/infrastructure/mcp/mcp-server.service.js +208 -207
- package/src/infrastructure/metrics/metrics.collector.js +140 -123
- package/src/infrastructure/providers/core/base-provider.js +87 -40
- package/src/infrastructure/providers/implementations/anthropic.js +101 -99
- package/src/infrastructure/providers/implementations/azure.js +124 -101
- package/src/infrastructure/providers/implementations/bedrock.js +136 -126
- package/src/infrastructure/providers/implementations/dummy.js +23 -23
- package/src/infrastructure/providers/implementations/google.js +123 -114
- package/src/infrastructure/providers/implementations/huggingface.js +94 -87
- package/src/infrastructure/providers/implementations/lmstudio.js +75 -60
- package/src/infrastructure/providers/implementations/mock.js +69 -73
- package/src/infrastructure/providers/implementations/ollama.js +89 -66
- package/src/infrastructure/providers/implementations/openai.js +88 -89
- package/src/infrastructure/providers/implementations/vertex.js +227 -197
- package/src/infrastructure/providers/provider-management.service.js +245 -207
- package/src/infrastructure/providers/provider-manager.service.js +145 -125
- package/src/infrastructure/providers/utils/base-provider-helpers.js +308 -302
- package/src/infrastructure/providers/utils/model-config.js +220 -195
- package/src/infrastructure/providers/utils/provider-utils.js +105 -100
- package/src/infrastructure/validation/commit-message-validation.service.js +259 -161
- package/src/shared/constants/colors.js +453 -180
- package/src/shared/utils/cli-demo.js +285 -0
- package/src/shared/utils/cli-entry-utils.js +257 -249
- package/src/shared/utils/cli-ui.js +447 -0
- package/src/shared/utils/diff-processor.js +513 -0
- package/src/shared/utils/error-classes.js +125 -156
- package/src/shared/utils/json-utils.js +93 -89
- package/src/shared/utils/utils.js +1117 -945
- package/types/index.d.ts +353 -344
|
@@ -4,40 +4,40 @@
|
|
|
4
4
|
* Supports multi-provider routing, chat completion, and latest models
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import { InferenceClient } from '@huggingface/inference'
|
|
8
|
-
|
|
9
|
-
import {
|
|
10
|
-
import { applyMixins } from '../utils/base-provider-helpers.js'
|
|
11
|
-
import { buildClientOptions } from '../utils/provider-utils.js'
|
|
7
|
+
import { InferenceClient } from '@huggingface/inference'
|
|
8
|
+
|
|
9
|
+
import { BaseProvider } from '../core/base-provider.js'
|
|
10
|
+
import { applyMixins } from '../utils/base-provider-helpers.js'
|
|
11
|
+
import { buildClientOptions } from '../utils/provider-utils.js'
|
|
12
12
|
|
|
13
13
|
class HuggingFaceProvider extends BaseProvider {
|
|
14
14
|
constructor(config) {
|
|
15
|
-
super(config)
|
|
16
|
-
this.client = null
|
|
15
|
+
super(config)
|
|
16
|
+
this.client = null
|
|
17
17
|
|
|
18
18
|
if (this.isAvailable()) {
|
|
19
|
-
this.initializeClient()
|
|
19
|
+
this.initializeClient()
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
initializeClient() {
|
|
24
24
|
const clientOptions = buildClientOptions(this.getProviderConfig(), {
|
|
25
|
-
timeout: 60000
|
|
26
|
-
})
|
|
25
|
+
timeout: 60000,
|
|
26
|
+
})
|
|
27
27
|
|
|
28
28
|
this.client = new InferenceClient({
|
|
29
29
|
token: clientOptions.apiKey,
|
|
30
30
|
endpointUrl: clientOptions.endpointUrl,
|
|
31
|
-
timeout: clientOptions.timeout
|
|
32
|
-
})
|
|
31
|
+
timeout: clientOptions.timeout,
|
|
32
|
+
})
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
getName() {
|
|
36
|
-
return 'huggingface'
|
|
36
|
+
return 'huggingface'
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
isAvailable() {
|
|
40
|
-
return !!this.config.HUGGINGFACE_API_KEY
|
|
40
|
+
return !!this.config.HUGGINGFACE_API_KEY
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
async generateCompletion(messages, options = {}) {
|
|
@@ -45,13 +45,13 @@ class HuggingFaceProvider extends BaseProvider {
|
|
|
45
45
|
return this.handleProviderError(
|
|
46
46
|
new Error('Hugging Face provider is not configured'),
|
|
47
47
|
'generate_completion'
|
|
48
|
-
)
|
|
48
|
+
)
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
try {
|
|
52
|
-
const modelConfig = this.getProviderModelConfig()
|
|
53
|
-
const modelId = options.model || modelConfig.standardModel
|
|
54
|
-
const provider = options.provider || 'auto'
|
|
52
|
+
const modelConfig = this.getProviderModelConfig()
|
|
53
|
+
const modelId = options.model || modelConfig.standardModel
|
|
54
|
+
const provider = options.provider || 'auto'
|
|
55
55
|
|
|
56
56
|
const params = {
|
|
57
57
|
model: modelId,
|
|
@@ -59,34 +59,34 @@ class HuggingFaceProvider extends BaseProvider {
|
|
|
59
59
|
max_tokens: options.max_tokens || 1000,
|
|
60
60
|
temperature: options.temperature || 0.3,
|
|
61
61
|
top_p: options.top_p || 0.95,
|
|
62
|
-
stream: false
|
|
63
|
-
}
|
|
62
|
+
stream: false,
|
|
63
|
+
}
|
|
64
64
|
|
|
65
65
|
if (provider && provider !== 'auto') {
|
|
66
|
-
params.provider = provider
|
|
66
|
+
params.provider = provider
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
if (options.tools && this.getCapabilities(modelId).function_calling) {
|
|
70
|
-
params.tools = this.formatTools(options.tools)
|
|
71
|
-
params.tool_choice = options.tool_choice || 'auto'
|
|
70
|
+
params.tools = this.formatTools(options.tools)
|
|
71
|
+
params.tool_choice = options.tool_choice || 'auto'
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
if (options.stream && typeof options.onStreamData === 'function') {
|
|
75
|
-
params.stream = true
|
|
75
|
+
params.stream = true
|
|
76
76
|
|
|
77
|
-
let fullContent = ''
|
|
78
|
-
const stream = this.client.chatCompletionStream(params)
|
|
77
|
+
let fullContent = ''
|
|
78
|
+
const stream = this.client.chatCompletionStream(params)
|
|
79
79
|
|
|
80
80
|
for await (const chunk of stream) {
|
|
81
|
-
const chunkContent = chunk.choices[0]?.delta?.content || ''
|
|
81
|
+
const chunkContent = chunk.choices[0]?.delta?.content || ''
|
|
82
82
|
if (chunkContent) {
|
|
83
|
-
fullContent += chunkContent
|
|
83
|
+
fullContent += chunkContent
|
|
84
84
|
options.onStreamData({
|
|
85
85
|
content: chunkContent,
|
|
86
86
|
model: modelId,
|
|
87
87
|
finish_reason: null,
|
|
88
|
-
done: false
|
|
89
|
-
})
|
|
88
|
+
done: false,
|
|
89
|
+
})
|
|
90
90
|
}
|
|
91
91
|
|
|
92
92
|
if (chunk.choices[0]?.finish_reason) {
|
|
@@ -94,9 +94,9 @@ class HuggingFaceProvider extends BaseProvider {
|
|
|
94
94
|
content: '',
|
|
95
95
|
model: modelId,
|
|
96
96
|
finish_reason: chunk.choices[0].finish_reason,
|
|
97
|
-
done: true
|
|
98
|
-
})
|
|
99
|
-
break
|
|
97
|
+
done: true,
|
|
98
|
+
})
|
|
99
|
+
break
|
|
100
100
|
}
|
|
101
101
|
}
|
|
102
102
|
|
|
@@ -104,77 +104,78 @@ class HuggingFaceProvider extends BaseProvider {
|
|
|
104
104
|
content: fullContent,
|
|
105
105
|
model: modelId,
|
|
106
106
|
tokens: this.estimateTokenCount(fullContent),
|
|
107
|
-
finish_reason: 'stop'
|
|
108
|
-
}
|
|
107
|
+
finish_reason: 'stop',
|
|
108
|
+
}
|
|
109
109
|
}
|
|
110
110
|
|
|
111
|
-
const response = await this.client.chatCompletion(params)
|
|
111
|
+
const response = await this.client.chatCompletion(params)
|
|
112
112
|
|
|
113
|
-
const choice = response.choices[0]
|
|
114
|
-
const content = choice.message.content
|
|
113
|
+
const choice = response.choices[0]
|
|
114
|
+
const content = choice.message.content
|
|
115
115
|
|
|
116
|
-
const toolCalls = choice.message.tool_calls
|
|
117
|
-
choice.message.tool_calls.map(call => ({
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
116
|
+
const toolCalls = choice.message.tool_calls
|
|
117
|
+
? choice.message.tool_calls.map((call) => ({
|
|
118
|
+
id: call.id,
|
|
119
|
+
type: call.type,
|
|
120
|
+
function: {
|
|
121
|
+
name: call.function.name,
|
|
122
|
+
arguments: call.function.arguments,
|
|
123
|
+
},
|
|
124
|
+
}))
|
|
125
|
+
: undefined
|
|
125
126
|
|
|
126
127
|
return {
|
|
127
|
-
content
|
|
128
|
+
content,
|
|
128
129
|
model: response.model || modelId,
|
|
129
130
|
tokens: response.usage?.total_tokens || this.estimateTokenCount(content),
|
|
130
131
|
finish_reason: choice.finish_reason || 'stop',
|
|
131
|
-
tool_calls: toolCalls
|
|
132
|
-
}
|
|
132
|
+
tool_calls: toolCalls,
|
|
133
|
+
}
|
|
133
134
|
} catch (error) {
|
|
134
135
|
if (error.message.includes('rate limit') || error.message.includes('quota')) {
|
|
135
|
-
console.warn('Hugging Face rate limit hit, implementing backoff...')
|
|
136
|
-
await this.sleep(2000)
|
|
136
|
+
console.warn('Hugging Face rate limit hit, implementing backoff...')
|
|
137
|
+
await this.sleep(2000)
|
|
137
138
|
}
|
|
138
139
|
|
|
139
|
-
return this.handleProviderError(error, 'generate_completion', { model: options.model })
|
|
140
|
+
return this.handleProviderError(error, 'generate_completion', { model: options.model })
|
|
140
141
|
}
|
|
141
142
|
}
|
|
142
143
|
|
|
143
144
|
// HuggingFace-specific helper methods
|
|
144
145
|
formatMessages(messages) {
|
|
145
|
-
return messages.map(msg => {
|
|
146
|
+
return messages.map((msg) => {
|
|
146
147
|
if (msg.role === 'system') {
|
|
147
|
-
return { role: 'system', content: msg.content }
|
|
148
|
+
return { role: 'system', content: msg.content }
|
|
148
149
|
}
|
|
149
150
|
return {
|
|
150
151
|
role: msg.role === 'assistant' ? 'assistant' : 'user',
|
|
151
|
-
content: typeof msg.content === 'string' ? msg.content : JSON.stringify(msg.content)
|
|
152
|
-
}
|
|
153
|
-
})
|
|
152
|
+
content: typeof msg.content === 'string' ? msg.content : JSON.stringify(msg.content),
|
|
153
|
+
}
|
|
154
|
+
})
|
|
154
155
|
}
|
|
155
156
|
|
|
156
157
|
formatTools(tools) {
|
|
157
|
-
return tools.map(tool => {
|
|
158
|
+
return tools.map((tool) => {
|
|
158
159
|
if (tool.type === 'function') {
|
|
159
160
|
return {
|
|
160
161
|
type: 'function',
|
|
161
162
|
function: {
|
|
162
163
|
name: tool.function.name,
|
|
163
164
|
description: tool.function.description || '',
|
|
164
|
-
parameters: tool.function.parameters || {}
|
|
165
|
-
}
|
|
166
|
-
}
|
|
165
|
+
parameters: tool.function.parameters || {},
|
|
166
|
+
},
|
|
167
|
+
}
|
|
167
168
|
}
|
|
168
|
-
return tool
|
|
169
|
-
})
|
|
169
|
+
return tool
|
|
170
|
+
})
|
|
170
171
|
}
|
|
171
172
|
|
|
172
173
|
estimateTokenCount(text) {
|
|
173
|
-
return Math.ceil(text.length / 4)
|
|
174
|
+
return Math.ceil(text.length / 4)
|
|
174
175
|
}
|
|
175
176
|
|
|
176
177
|
sleep(ms) {
|
|
177
|
-
return new Promise(resolve => setTimeout(resolve, ms))
|
|
178
|
+
return new Promise((resolve) => setTimeout(resolve, ms))
|
|
178
179
|
}
|
|
179
180
|
|
|
180
181
|
getAvailableModels() {
|
|
@@ -189,7 +190,7 @@ class HuggingFaceProvider extends BaseProvider {
|
|
|
189
190
|
outputCost: 0.000009,
|
|
190
191
|
features: ['text', 'tools', 'multilingual'],
|
|
191
192
|
description: 'Latest Qwen model with enhanced capabilities',
|
|
192
|
-
provider: 'auto'
|
|
193
|
+
provider: 'auto',
|
|
193
194
|
},
|
|
194
195
|
{
|
|
195
196
|
id: 'meta-llama/Llama-3.3-70B-Instruct',
|
|
@@ -200,7 +201,7 @@ class HuggingFaceProvider extends BaseProvider {
|
|
|
200
201
|
outputCost: 0.000006,
|
|
201
202
|
features: ['text', 'tools', 'reasoning'],
|
|
202
203
|
description: 'Latest Llama 3.3 with improved reasoning',
|
|
203
|
-
provider: 'together'
|
|
204
|
+
provider: 'together',
|
|
204
205
|
},
|
|
205
206
|
{
|
|
206
207
|
id: 'meta-llama/Llama-3.1-405B-Instruct',
|
|
@@ -211,7 +212,7 @@ class HuggingFaceProvider extends BaseProvider {
|
|
|
211
212
|
outputCost: 0.000015,
|
|
212
213
|
features: ['text', 'tools', 'reasoning'],
|
|
213
214
|
description: 'Most capable Llama model from Meta AI',
|
|
214
|
-
provider: 'replicate'
|
|
215
|
+
provider: 'replicate',
|
|
215
216
|
},
|
|
216
217
|
{
|
|
217
218
|
id: 'mistralai/Mixtral-8x22B-Instruct-v0.1',
|
|
@@ -222,7 +223,7 @@ class HuggingFaceProvider extends BaseProvider {
|
|
|
222
223
|
outputCost: 0.0000027,
|
|
223
224
|
features: ['text', 'tools', 'multilingual'],
|
|
224
225
|
description: 'Large mixture of experts model from Mistral',
|
|
225
|
-
provider: 'together'
|
|
226
|
+
provider: 'together',
|
|
226
227
|
},
|
|
227
228
|
{
|
|
228
229
|
id: 'microsoft/WizardLM-2-8x22B',
|
|
@@ -233,28 +234,28 @@ class HuggingFaceProvider extends BaseProvider {
|
|
|
233
234
|
outputCost: 0.000003,
|
|
234
235
|
features: ['text', 'reasoning', 'complex_tasks'],
|
|
235
236
|
description: 'Advanced reasoning model from Microsoft',
|
|
236
|
-
provider: 'sambanova'
|
|
237
|
+
provider: 'sambanova',
|
|
237
238
|
},
|
|
238
239
|
{
|
|
239
240
|
id: 'black-forest-labs/FLUX.1-dev',
|
|
240
241
|
name: 'FLUX.1 Dev',
|
|
241
242
|
contextWindow: 0,
|
|
242
243
|
maxOutput: 0,
|
|
243
|
-
inputCost: 0.
|
|
244
|
-
outputCost: 0.
|
|
244
|
+
inputCost: 0.00005,
|
|
245
|
+
outputCost: 0.00005,
|
|
245
246
|
features: ['text_to_image', 'high_quality'],
|
|
246
247
|
description: 'State-of-the-art text-to-image generation',
|
|
247
|
-
provider: 'replicate'
|
|
248
|
-
}
|
|
249
|
-
]
|
|
248
|
+
provider: 'replicate',
|
|
249
|
+
},
|
|
250
|
+
]
|
|
250
251
|
}
|
|
251
252
|
|
|
252
253
|
getDefaultModel() {
|
|
253
|
-
return 'Qwen/Qwen2.5-72B-Instruct'
|
|
254
|
+
return 'Qwen/Qwen2.5-72B-Instruct'
|
|
254
255
|
}
|
|
255
256
|
|
|
256
257
|
getRequiredEnvVars() {
|
|
257
|
-
return ['HUGGINGFACE_API_KEY']
|
|
258
|
+
return ['HUGGINGFACE_API_KEY']
|
|
258
259
|
}
|
|
259
260
|
|
|
260
261
|
getProviderModelConfig() {
|
|
@@ -267,21 +268,27 @@ class HuggingFaceProvider extends BaseProvider {
|
|
|
267
268
|
multilingualModel: 'mistralai/Mixtral-8x22B-Instruct-v0.1',
|
|
268
269
|
default: 'Qwen/Qwen2.5-72B-Instruct',
|
|
269
270
|
temperature: 0.3,
|
|
270
|
-
maxTokens: 1000
|
|
271
|
-
}
|
|
271
|
+
maxTokens: 1000,
|
|
272
|
+
}
|
|
272
273
|
}
|
|
273
274
|
|
|
274
275
|
getModelCapabilities(modelName) {
|
|
275
276
|
return {
|
|
276
|
-
reasoning:
|
|
277
|
+
reasoning:
|
|
278
|
+
modelName.includes('Llama-3') ||
|
|
279
|
+
modelName.includes('WizardLM') ||
|
|
280
|
+
modelName.includes('Qwen'),
|
|
277
281
|
function_calling: modelName.includes('Instruct') && !modelName.includes('FLUX'),
|
|
278
282
|
json_mode: true,
|
|
279
283
|
multimodal: modelName.includes('FLUX'),
|
|
280
|
-
largeContext:
|
|
284
|
+
largeContext:
|
|
285
|
+
modelName.includes('Llama-3.3') ||
|
|
286
|
+
modelName.includes('Mixtral') ||
|
|
287
|
+
modelName.includes('Qwen'),
|
|
281
288
|
multilingual: modelName.includes('Qwen') || modelName.includes('Mixtral'),
|
|
282
289
|
multiProvider: true,
|
|
283
|
-
imageGeneration: modelName.includes('FLUX')
|
|
284
|
-
}
|
|
290
|
+
imageGeneration: modelName.includes('FLUX'),
|
|
291
|
+
}
|
|
285
292
|
}
|
|
286
293
|
|
|
287
294
|
getCapabilities(modelName) {
|
|
@@ -292,10 +299,10 @@ class HuggingFaceProvider extends BaseProvider {
|
|
|
292
299
|
json_mode: true,
|
|
293
300
|
reasoning: modelName ? this.getModelCapabilities(modelName).reasoning : true,
|
|
294
301
|
multimodal: modelName ? this.getModelCapabilities(modelName).multimodal : false,
|
|
295
|
-
multiProvider: true
|
|
296
|
-
}
|
|
302
|
+
multiProvider: true,
|
|
303
|
+
}
|
|
297
304
|
}
|
|
298
305
|
}
|
|
299
306
|
|
|
300
307
|
// Apply mixins to add standard provider functionality
|
|
301
|
-
export default applyMixins(HuggingFaceProvider, 'huggingface')
|
|
308
|
+
export default applyMixins(HuggingFaceProvider, 'huggingface')
|
|
@@ -1,14 +1,15 @@
|
|
|
1
|
-
import { OpenAI } from 'openai'
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
1
|
+
import { OpenAI } from 'openai'
|
|
2
|
+
|
|
3
|
+
import { BaseProvider } from '../core/base-provider.js'
|
|
4
|
+
import { applyMixins } from '../utils/base-provider-helpers.js'
|
|
5
|
+
import { buildClientOptions } from '../utils/provider-utils.js'
|
|
5
6
|
|
|
6
7
|
class LMStudioProvider extends BaseProvider {
|
|
7
8
|
constructor(config) {
|
|
8
|
-
super(config)
|
|
9
|
-
this.client = null
|
|
9
|
+
super(config)
|
|
10
|
+
this.client = null
|
|
10
11
|
if (this.isAvailable()) {
|
|
11
|
-
this.initializeClient()
|
|
12
|
+
this.initializeClient()
|
|
12
13
|
}
|
|
13
14
|
}
|
|
14
15
|
|
|
@@ -17,71 +18,79 @@ class LMStudioProvider extends BaseProvider {
|
|
|
17
18
|
baseURL: 'http://localhost:1234/v1',
|
|
18
19
|
apiKey: 'lm-studio', // Not required by LM Studio
|
|
19
20
|
timeout: 120000,
|
|
20
|
-
maxRetries: 2
|
|
21
|
-
})
|
|
22
|
-
|
|
21
|
+
maxRetries: 2,
|
|
22
|
+
})
|
|
23
|
+
|
|
23
24
|
// LM Studio uses OpenAI-compatible API
|
|
24
25
|
this.client = new OpenAI({
|
|
25
26
|
baseURL: clientOptions.baseURL,
|
|
26
27
|
apiKey: clientOptions.apiKey,
|
|
27
28
|
timeout: clientOptions.timeout,
|
|
28
29
|
maxRetries: clientOptions.maxRetries,
|
|
29
|
-
})
|
|
30
|
+
})
|
|
30
31
|
}
|
|
31
32
|
|
|
32
33
|
getName() {
|
|
33
|
-
return 'lmstudio'
|
|
34
|
+
return 'lmstudio'
|
|
34
35
|
}
|
|
35
36
|
|
|
36
37
|
isAvailable() {
|
|
37
|
-
return !!this.config.LMSTUDIO_API_BASE
|
|
38
|
+
return !!this.config.LMSTUDIO_API_BASE
|
|
38
39
|
}
|
|
39
40
|
|
|
40
41
|
async generateCompletion(messages, options) {
|
|
41
42
|
if (!this.isAvailable()) {
|
|
42
43
|
return this.handleProviderError(
|
|
43
|
-
new Error('LM Studio provider is not configured'),
|
|
44
|
+
new Error('LM Studio provider is not configured'),
|
|
44
45
|
'generate_completion'
|
|
45
|
-
)
|
|
46
|
+
)
|
|
46
47
|
}
|
|
47
48
|
|
|
48
49
|
// Prepare parameters for the API call
|
|
49
50
|
const params = {
|
|
50
|
-
model:
|
|
51
|
-
|
|
51
|
+
model:
|
|
52
|
+
options.model ||
|
|
53
|
+
this.config.AI_MODEL ||
|
|
54
|
+
this.config.LMSTUDIO_MODEL ||
|
|
55
|
+
this.config.LMSTUDIO_DEFAULT_MODEL ||
|
|
56
|
+
'local-model',
|
|
57
|
+
messages,
|
|
52
58
|
max_tokens: options.max_tokens || 2048,
|
|
53
59
|
temperature: options.temperature || 0.7,
|
|
54
60
|
top_p: options.top_p || 0.95,
|
|
55
61
|
frequency_penalty: options.frequency_penalty || 0,
|
|
56
62
|
presence_penalty: options.presence_penalty || 0,
|
|
57
|
-
user: options.user || this.config.LMSTUDIO_USER_ID
|
|
58
|
-
}
|
|
63
|
+
user: options.user || this.config.LMSTUDIO_USER_ID,
|
|
64
|
+
}
|
|
59
65
|
|
|
60
66
|
// Add function calling if provided and the model supports it
|
|
61
67
|
if (options.tools && this.getCapabilities(params.model).tool_use) {
|
|
62
|
-
params.tools = options.tools
|
|
63
|
-
params.tool_choice = options.tool_choice || 'auto'
|
|
68
|
+
params.tools = options.tools
|
|
69
|
+
params.tool_choice = options.tool_choice || 'auto'
|
|
64
70
|
}
|
|
65
71
|
|
|
66
72
|
// Add JSON mode if requested and the model supports it
|
|
67
|
-
if (
|
|
68
|
-
|
|
73
|
+
if (
|
|
74
|
+
options.response_format?.type === 'json_object' &&
|
|
75
|
+
this.getCapabilities(params.model).json_mode
|
|
76
|
+
) {
|
|
77
|
+
params.response_format = { type: 'json_object' }
|
|
69
78
|
}
|
|
70
79
|
|
|
71
80
|
// Handle streaming
|
|
72
81
|
if (options.stream) {
|
|
73
|
-
params.stream = true
|
|
74
|
-
const stream = await this.client.chat.completions.create(params)
|
|
75
|
-
return { stream, model: params.model }
|
|
82
|
+
params.stream = true
|
|
83
|
+
const stream = await this.client.chat.completions.create(params)
|
|
84
|
+
return { stream, model: params.model }
|
|
76
85
|
}
|
|
77
86
|
|
|
78
87
|
// Make the non-streaming API call
|
|
79
|
-
const response = await this.client.chat.completions.create(params)
|
|
88
|
+
const response = await this.client.chat.completions.create(params)
|
|
80
89
|
|
|
81
90
|
// Extract tool calls if present
|
|
82
|
-
let toolCalls = null
|
|
91
|
+
let toolCalls = null
|
|
83
92
|
if (response.choices[0]?.message?.tool_calls?.length > 0) {
|
|
84
|
-
toolCalls = response.choices[0].message.tool_calls
|
|
93
|
+
toolCalls = response.choices[0].message.tool_calls
|
|
85
94
|
}
|
|
86
95
|
|
|
87
96
|
return {
|
|
@@ -89,54 +98,60 @@ class LMStudioProvider extends BaseProvider {
|
|
|
89
98
|
model: response.model,
|
|
90
99
|
tokens: response.usage?.total_tokens || 0,
|
|
91
100
|
finish_reason: response.choices[0].finish_reason,
|
|
92
|
-
tool_calls: toolCalls
|
|
93
|
-
}
|
|
101
|
+
tool_calls: toolCalls,
|
|
102
|
+
}
|
|
94
103
|
}
|
|
95
104
|
|
|
96
|
-
|
|
97
105
|
getCapabilities(modelName) {
|
|
98
|
-
const model =
|
|
99
|
-
|
|
106
|
+
const model =
|
|
107
|
+
modelName ||
|
|
108
|
+
this.config.AI_MODEL ||
|
|
109
|
+
this.config.LMSTUDIO_MODEL ||
|
|
110
|
+
this.config.LMSTUDIO_DEFAULT_MODEL ||
|
|
111
|
+
'local-model'
|
|
112
|
+
|
|
100
113
|
// Base capabilities - all models are local
|
|
101
114
|
const capabilities = {
|
|
102
115
|
vision: false,
|
|
103
116
|
tool_use: false,
|
|
104
117
|
json_mode: false,
|
|
105
118
|
reasoning: false,
|
|
106
|
-
local: true
|
|
107
|
-
}
|
|
108
|
-
|
|
119
|
+
local: true,
|
|
120
|
+
}
|
|
121
|
+
|
|
109
122
|
// Capabilities depend on the specific model loaded in LM Studio
|
|
110
123
|
// These are general capabilities based on model family naming conventions
|
|
111
|
-
|
|
124
|
+
|
|
112
125
|
// Llama models
|
|
113
126
|
if (model.toLowerCase().includes('llama')) {
|
|
114
|
-
capabilities.json_mode = true
|
|
115
|
-
|
|
127
|
+
capabilities.json_mode = true
|
|
128
|
+
|
|
116
129
|
// Llama 3 models likely support function calling
|
|
117
130
|
if (model.includes('3')) {
|
|
118
|
-
capabilities.tool_use = true
|
|
131
|
+
capabilities.tool_use = true
|
|
119
132
|
}
|
|
120
133
|
}
|
|
121
|
-
|
|
134
|
+
|
|
122
135
|
// Mistral models
|
|
123
136
|
else if (model.toLowerCase().includes('mistral')) {
|
|
124
|
-
capabilities.json_mode = true
|
|
125
|
-
|
|
137
|
+
capabilities.json_mode = true
|
|
138
|
+
|
|
126
139
|
// Mixtral models likely have better reasoning
|
|
127
140
|
if (model.toLowerCase().includes('mixtral')) {
|
|
128
|
-
capabilities.reasoning = true
|
|
141
|
+
capabilities.reasoning = true
|
|
129
142
|
}
|
|
130
143
|
}
|
|
131
|
-
|
|
144
|
+
|
|
132
145
|
// Vision models
|
|
133
|
-
if (
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
146
|
+
if (
|
|
147
|
+
model.toLowerCase().includes('vision') ||
|
|
148
|
+
model.toLowerCase().includes('llava') ||
|
|
149
|
+
model.toLowerCase().includes('bakllava')
|
|
150
|
+
) {
|
|
151
|
+
capabilities.vision = true
|
|
137
152
|
}
|
|
138
|
-
|
|
139
|
-
return capabilities
|
|
153
|
+
|
|
154
|
+
return capabilities
|
|
140
155
|
}
|
|
141
156
|
|
|
142
157
|
getAvailableModels() {
|
|
@@ -146,10 +161,10 @@ class LMStudioProvider extends BaseProvider {
|
|
|
146
161
|
name: 'Local Model (LM Studio)',
|
|
147
162
|
contextWindow: 4096,
|
|
148
163
|
maxOutput: 2048,
|
|
149
|
-
inputCost: 0,
|
|
164
|
+
inputCost: 0, // Local models are free
|
|
150
165
|
outputCost: 0,
|
|
151
166
|
features: ['text', 'local'],
|
|
152
|
-
description: 'Local model running in LM Studio'
|
|
167
|
+
description: 'Local model running in LM Studio',
|
|
153
168
|
},
|
|
154
169
|
{
|
|
155
170
|
id: 'llama-3-8b-instruct',
|
|
@@ -159,7 +174,7 @@ class LMStudioProvider extends BaseProvider {
|
|
|
159
174
|
inputCost: 0,
|
|
160
175
|
outputCost: 0,
|
|
161
176
|
features: ['text', 'tools', 'local'],
|
|
162
|
-
description: 'Local Llama 3 8B instruction-tuned model'
|
|
177
|
+
description: 'Local Llama 3 8B instruction-tuned model',
|
|
163
178
|
},
|
|
164
179
|
{
|
|
165
180
|
id: 'mistral-7b-instruct',
|
|
@@ -169,7 +184,7 @@ class LMStudioProvider extends BaseProvider {
|
|
|
169
184
|
inputCost: 0,
|
|
170
185
|
outputCost: 0,
|
|
171
186
|
features: ['text', 'reasoning', 'local'],
|
|
172
|
-
description: 'Local Mistral 7B instruction-tuned model'
|
|
187
|
+
description: 'Local Mistral 7B instruction-tuned model',
|
|
173
188
|
},
|
|
174
189
|
{
|
|
175
190
|
id: 'llava-1.5-7b',
|
|
@@ -179,11 +194,11 @@ class LMStudioProvider extends BaseProvider {
|
|
|
179
194
|
inputCost: 0,
|
|
180
195
|
outputCost: 0,
|
|
181
196
|
features: ['text', 'vision', 'local'],
|
|
182
|
-
description: 'Local vision-language model'
|
|
183
|
-
}
|
|
184
|
-
]
|
|
197
|
+
description: 'Local vision-language model',
|
|
198
|
+
},
|
|
199
|
+
]
|
|
185
200
|
}
|
|
186
201
|
}
|
|
187
202
|
|
|
188
203
|
// Apply mixins to add standard provider functionality
|
|
189
|
-
export default applyMixins(LMStudioProvider, 'lmstudio')
|
|
204
|
+
export default applyMixins(LMStudioProvider, 'lmstudio')
|