@howlil/ez-agents 3.4.1 → 3.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -21
- package/README.md +7 -18
- package/bin/install.js +52 -10
- package/commands/ez/join-discord.md +18 -18
- package/ez-agents/bin/lib/assistant-adapter.cjs +264 -264
- package/ez-agents/bin/lib/audit-exec.cjs +7 -2
- package/ez-agents/bin/lib/circuit-breaker.cjs +118 -118
- package/ez-agents/bin/lib/config.cjs +190 -190
- package/ez-agents/bin/lib/file-lock.cjs +236 -236
- package/ez-agents/bin/lib/frontmatter.cjs +299 -299
- package/ez-agents/bin/lib/fs-utils.cjs +153 -153
- package/ez-agents/bin/lib/git-utils.cjs +203 -203
- package/ez-agents/bin/lib/index.cjs +113 -113
- package/ez-agents/bin/lib/init.cjs +757 -757
- package/ez-agents/bin/lib/logger.cjs +47 -17
- package/ez-agents/bin/lib/milestone.cjs +241 -241
- package/ez-agents/bin/lib/model-provider.cjs +241 -241
- package/ez-agents/bin/lib/phase.cjs +925 -925
- package/ez-agents/bin/lib/planning-write.cjs +107 -107
- package/ez-agents/bin/lib/retry.cjs +119 -119
- package/ez-agents/bin/lib/roadmap.cjs +306 -306
- package/ez-agents/bin/lib/safe-exec.cjs +90 -4
- package/ez-agents/bin/lib/safe-path.cjs +130 -130
- package/ez-agents/bin/lib/state.cjs +736 -736
- package/ez-agents/bin/lib/temp-file.cjs +239 -239
- package/ez-agents/bin/lib/template.cjs +223 -223
- package/ez-agents/bin/lib/test-file-lock.cjs +112 -112
- package/ez-agents/bin/lib/test-graceful.cjs +93 -93
- package/ez-agents/bin/lib/test-logger.cjs +60 -60
- package/ez-agents/bin/lib/test-safe-exec.cjs +38 -38
- package/ez-agents/bin/lib/test-safe-path.cjs +33 -33
- package/ez-agents/bin/lib/test-temp-file.cjs +125 -125
- package/ez-agents/bin/lib/timeout-exec.cjs +63 -63
- package/ez-agents/bin/lib/verify.cjs +15 -1
- package/ez-agents/references/checkpoints.md +776 -776
- package/ez-agents/references/continuation-format.md +249 -249
- package/ez-agents/references/questioning.md +162 -162
- package/ez-agents/references/tdd.md +263 -263
- package/ez-agents/templates/codebase/concerns.md +310 -310
- package/ez-agents/templates/codebase/conventions.md +307 -307
- package/ez-agents/templates/codebase/integrations.md +280 -280
- package/ez-agents/templates/codebase/stack.md +186 -186
- package/ez-agents/templates/codebase/testing.md +480 -480
- package/ez-agents/templates/config.json +37 -37
- package/ez-agents/templates/continue-here.md +78 -78
- package/ez-agents/templates/milestone-archive.md +123 -123
- package/ez-agents/templates/milestone.md +115 -115
- package/ez-agents/templates/requirements.md +231 -231
- package/ez-agents/templates/research-project/ARCHITECTURE.md +204 -204
- package/ez-agents/templates/research-project/FEATURES.md +147 -147
- package/ez-agents/templates/research-project/PITFALLS.md +200 -200
- package/ez-agents/templates/research-project/STACK.md +120 -120
- package/ez-agents/templates/research-project/SUMMARY.md +170 -170
- package/ez-agents/templates/retrospective.md +54 -54
- package/ez-agents/templates/roadmap.md +202 -202
- package/ez-agents/templates/summary-minimal.md +41 -41
- package/ez-agents/templates/summary-standard.md +48 -48
- package/ez-agents/templates/summary.md +248 -248
- package/ez-agents/templates/user-setup.md +311 -311
- package/ez-agents/templates/verification-report.md +322 -322
- package/ez-agents/workflows/add-phase.md +112 -112
- package/ez-agents/workflows/add-tests.md +351 -351
- package/ez-agents/workflows/add-todo.md +158 -158
- package/ez-agents/workflows/audit-milestone.md +332 -332
- package/ez-agents/workflows/autonomous.md +743 -743
- package/ez-agents/workflows/check-todos.md +177 -177
- package/ez-agents/workflows/cleanup.md +152 -152
- package/ez-agents/workflows/complete-milestone.md +766 -766
- package/ez-agents/workflows/diagnose-issues.md +219 -219
- package/ez-agents/workflows/discovery-phase.md +289 -289
- package/ez-agents/workflows/discuss-phase.md +762 -762
- package/ez-agents/workflows/execute-phase.md +468 -468
- package/ez-agents/workflows/execute-plan.md +483 -483
- package/ez-agents/workflows/health.md +159 -159
- package/ez-agents/workflows/help.md +492 -492
- package/ez-agents/workflows/insert-phase.md +130 -130
- package/ez-agents/workflows/list-phase-assumptions.md +178 -178
- package/ez-agents/workflows/map-codebase.md +316 -316
- package/ez-agents/workflows/new-milestone.md +384 -384
- package/ez-agents/workflows/new-project.md +1113 -1113
- package/ez-agents/workflows/node-repair.md +92 -92
- package/ez-agents/workflows/pause-work.md +122 -122
- package/ez-agents/workflows/plan-milestone-gaps.md +274 -274
- package/ez-agents/workflows/plan-phase.md +651 -651
- package/ez-agents/workflows/progress.md +382 -382
- package/ez-agents/workflows/quick.md +610 -610
- package/ez-agents/workflows/remove-phase.md +155 -155
- package/ez-agents/workflows/research-phase.md +74 -74
- package/ez-agents/workflows/resume-project.md +307 -307
- package/ez-agents/workflows/set-profile.md +81 -81
- package/ez-agents/workflows/settings.md +242 -242
- package/ez-agents/workflows/stats.md +57 -57
- package/ez-agents/workflows/transition.md +544 -544
- package/ez-agents/workflows/ui-phase.md +290 -290
- package/ez-agents/workflows/ui-review.md +157 -157
- package/ez-agents/workflows/update.md +320 -320
- package/ez-agents/workflows/validate-phase.md +167 -167
- package/ez-agents/workflows/verify-phase.md +243 -243
- package/ez-agents/workflows/verify-work.md +584 -584
- package/package.json +2 -3
- package/scripts/build-hooks.js +43 -43
- package/scripts/run-tests.cjs +29 -29
|
@@ -1,241 +1,241 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* EZ Model Provider — Unified API for multiple AI providers
|
|
5
|
-
*
|
|
6
|
-
* Supports: Anthropic, Moonshot (Kimi), Alibaba (Qwen), OpenAI
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
const https = require('https');
|
|
10
|
-
const { URL } = require('url');
|
|
11
|
-
const Logger = require('./logger.cjs');
|
|
12
|
-
const logger = new Logger();
|
|
13
|
-
|
|
14
|
-
class ModelProvider {
|
|
15
|
-
/**
|
|
16
|
-
* Create model provider
|
|
17
|
-
* @param {Object} config - Configuration
|
|
18
|
-
*/
|
|
19
|
-
constructor(config) {
|
|
20
|
-
this.provider = config.provider || 'anthropic';
|
|
21
|
-
this.model = config.model || 'sonnet';
|
|
22
|
-
this.apiKey = config.apiKey || process.env[`${this.provider.toUpperCase()}_API_KEY`];
|
|
23
|
-
|
|
24
|
-
if (!this.apiKey && this.provider !== 'anthropic') {
|
|
25
|
-
logger.warn('API key not configured', { provider: this.provider });
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Helper for HTTP requests
|
|
31
|
-
*/
|
|
32
|
-
_httpRequest(options, data) {
|
|
33
|
-
return new Promise((resolve, reject) => {
|
|
34
|
-
const req = https.request(options, (res) => {
|
|
35
|
-
let body = '';
|
|
36
|
-
res.on('data', (chunk) => body += chunk);
|
|
37
|
-
res.on('end', () => {
|
|
38
|
-
if (res.statusCode >= 200 && res.statusCode < 300) {
|
|
39
|
-
try {
|
|
40
|
-
resolve(JSON.parse(body));
|
|
41
|
-
} catch (e) {
|
|
42
|
-
resolve(body);
|
|
43
|
-
}
|
|
44
|
-
} else {
|
|
45
|
-
reject(new Error(`HTTP ${res.statusCode}: ${body}`));
|
|
46
|
-
}
|
|
47
|
-
});
|
|
48
|
-
});
|
|
49
|
-
req.on('error', reject);
|
|
50
|
-
if (data) req.write(JSON.stringify(data));
|
|
51
|
-
req.end();
|
|
52
|
-
});
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Send chat message
|
|
57
|
-
* @param {Object[]} messages - Chat messages
|
|
58
|
-
* @param {Object} options - Chat options
|
|
59
|
-
* @returns {Promise<Object>} - Response
|
|
60
|
-
*/
|
|
61
|
-
async chat(messages, options = {}) {
|
|
62
|
-
logger.info('Chat request', {
|
|
63
|
-
provider: this.provider,
|
|
64
|
-
model: this.model,
|
|
65
|
-
messageCount: messages.length
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
switch (this.provider) {
|
|
69
|
-
case 'anthropic':
|
|
70
|
-
return this._chatAnthropic(messages, options);
|
|
71
|
-
case 'moonshot':
|
|
72
|
-
return this._chatMoonshot(messages, options);
|
|
73
|
-
case 'alibaba':
|
|
74
|
-
case 'qwen':
|
|
75
|
-
return this._chatQwen(messages, options);
|
|
76
|
-
case 'openai':
|
|
77
|
-
return this._chatOpenAI(messages, options);
|
|
78
|
-
default:
|
|
79
|
-
throw new Error(`Unsupported provider: ${this.provider}`);
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* Anthropic Claude API
|
|
85
|
-
*/
|
|
86
|
-
async _chatAnthropic(messages, options) {
|
|
87
|
-
// Anthropic usually requires their SDK or complex headers
|
|
88
|
-
logger.debug('Anthropic chat', { model: this.model });
|
|
89
|
-
return {
|
|
90
|
-
content: '[Anthropic response placeholder - requires SDK]',
|
|
91
|
-
provider: 'anthropic',
|
|
92
|
-
model: this.model
|
|
93
|
-
};
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* Moonshot (Kimi) API
|
|
98
|
-
*/
|
|
99
|
-
async _chatMoonshot(messages, options) {
|
|
100
|
-
const modelName = this.model === 'sonnet' ? 'moonshot-v1-8k' : this.model;
|
|
101
|
-
const data = {
|
|
102
|
-
model: modelName,
|
|
103
|
-
messages: messages,
|
|
104
|
-
temperature: options.temperature || 0.3
|
|
105
|
-
};
|
|
106
|
-
|
|
107
|
-
const reqOptions = {
|
|
108
|
-
hostname: 'api.moonshot.cn',
|
|
109
|
-
path: '/v1/chat/completions',
|
|
110
|
-
method: 'POST',
|
|
111
|
-
headers: {
|
|
112
|
-
'Content-Type': 'application/json',
|
|
113
|
-
'Authorization': `Bearer ${this.apiKey}`
|
|
114
|
-
}
|
|
115
|
-
};
|
|
116
|
-
|
|
117
|
-
try {
|
|
118
|
-
const response = await this._httpRequest(reqOptions, data);
|
|
119
|
-
return {
|
|
120
|
-
content: response.choices[0].message.content,
|
|
121
|
-
provider: 'moonshot',
|
|
122
|
-
model: modelName
|
|
123
|
-
};
|
|
124
|
-
} catch (error) {
|
|
125
|
-
logger.error('Moonshot API error', { error: error.message });
|
|
126
|
-
throw error;
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
/**
|
|
131
|
-
* Alibaba Qwen API (DashScope)
|
|
132
|
-
*/
|
|
133
|
-
async _chatQwen(messages, options) {
|
|
134
|
-
// Map generic model names to Qwen specific ones
|
|
135
|
-
let modelName = this.model;
|
|
136
|
-
if (modelName === 'sonnet' || modelName === 'gpt-4') modelName = 'qwen-max';
|
|
137
|
-
if (modelName === 'haiku' || modelName === 'gpt-3.5-turbo') modelName = 'qwen-plus';
|
|
138
|
-
|
|
139
|
-
const data = {
|
|
140
|
-
model: modelName,
|
|
141
|
-
input: {
|
|
142
|
-
messages: messages
|
|
143
|
-
},
|
|
144
|
-
parameters: {
|
|
145
|
-
result_format: 'message',
|
|
146
|
-
temperature: options.temperature || 0.3
|
|
147
|
-
}
|
|
148
|
-
};
|
|
149
|
-
|
|
150
|
-
const reqOptions = {
|
|
151
|
-
hostname: 'dashscope.aliyuncs.com',
|
|
152
|
-
path: '/api/v1/services/aigc/text-generation/generation',
|
|
153
|
-
method: 'POST',
|
|
154
|
-
headers: {
|
|
155
|
-
'Content-Type': 'application/json',
|
|
156
|
-
'Authorization': `Bearer ${this.apiKey}`
|
|
157
|
-
}
|
|
158
|
-
};
|
|
159
|
-
|
|
160
|
-
try {
|
|
161
|
-
const response = await this._httpRequest(reqOptions, data);
|
|
162
|
-
return {
|
|
163
|
-
content: response.output.choices[0].message.content,
|
|
164
|
-
provider: 'alibaba',
|
|
165
|
-
model: modelName
|
|
166
|
-
};
|
|
167
|
-
} catch (error) {
|
|
168
|
-
logger.error('Qwen API error', { error: error.message });
|
|
169
|
-
throw error;
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
/**
|
|
174
|
-
* OpenAI API
|
|
175
|
-
*/
|
|
176
|
-
async _chatOpenAI(messages, options) {
|
|
177
|
-
const modelName = this.model === 'sonnet' ? 'gpt-4-turbo' : this.model;
|
|
178
|
-
const data = {
|
|
179
|
-
model: modelName,
|
|
180
|
-
messages: messages,
|
|
181
|
-
temperature: options.temperature || 0.3
|
|
182
|
-
};
|
|
183
|
-
|
|
184
|
-
const reqOptions = {
|
|
185
|
-
hostname: 'api.openai.com',
|
|
186
|
-
path: '/v1/chat/completions',
|
|
187
|
-
method: 'POST',
|
|
188
|
-
headers: {
|
|
189
|
-
'Content-Type': 'application/json',
|
|
190
|
-
'Authorization': `Bearer ${this.apiKey}`
|
|
191
|
-
}
|
|
192
|
-
};
|
|
193
|
-
|
|
194
|
-
try {
|
|
195
|
-
const response = await this._httpRequest(reqOptions, data);
|
|
196
|
-
return {
|
|
197
|
-
content: response.choices[0].message.content,
|
|
198
|
-
provider: 'openai',
|
|
199
|
-
model: modelName
|
|
200
|
-
};
|
|
201
|
-
} catch (error) {
|
|
202
|
-
logger.error('OpenAI API error', { error: error.message });
|
|
203
|
-
throw error;
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
/**
|
|
208
|
-
* Count tokens (approximate)
|
|
209
|
-
* @param {string} text - Text to count
|
|
210
|
-
* @returns {number} - Approximate token count
|
|
211
|
-
*/
|
|
212
|
-
countTokens(text) {
|
|
213
|
-
return Math.ceil(text.length / 4);
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
/**
|
|
217
|
-
* Get provider info
|
|
218
|
-
* @returns {Object} - Provider information
|
|
219
|
-
*/
|
|
220
|
-
getInfo() {
|
|
221
|
-
return {
|
|
222
|
-
provider: this.provider,
|
|
223
|
-
model: this.model,
|
|
224
|
-
hasApiKey: !!this.apiKey
|
|
225
|
-
};
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
/**
|
|
230
|
-
* Create provider from config
|
|
231
|
-
* @param {Object} config - Provider config
|
|
232
|
-
* @returns {ModelProvider} - Model provider instance
|
|
233
|
-
*/
|
|
234
|
-
function createProvider(config) {
|
|
235
|
-
return new ModelProvider(config);
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
module.exports = {
|
|
239
|
-
ModelProvider,
|
|
240
|
-
createProvider
|
|
241
|
-
};
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* EZ Model Provider — Unified API for multiple AI providers
|
|
5
|
+
*
|
|
6
|
+
* Supports: Anthropic, Moonshot (Kimi), Alibaba (Qwen), OpenAI
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const https = require('https');
|
|
10
|
+
const { URL } = require('url');
|
|
11
|
+
const Logger = require('./logger.cjs');
|
|
12
|
+
const logger = new Logger();
|
|
13
|
+
|
|
14
|
+
class ModelProvider {
|
|
15
|
+
/**
|
|
16
|
+
* Create model provider
|
|
17
|
+
* @param {Object} config - Configuration
|
|
18
|
+
*/
|
|
19
|
+
constructor(config) {
|
|
20
|
+
this.provider = config.provider || 'anthropic';
|
|
21
|
+
this.model = config.model || 'sonnet';
|
|
22
|
+
this.apiKey = config.apiKey || process.env[`${this.provider.toUpperCase()}_API_KEY`];
|
|
23
|
+
|
|
24
|
+
if (!this.apiKey && this.provider !== 'anthropic') {
|
|
25
|
+
logger.warn('API key not configured', { provider: this.provider });
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Helper for HTTP requests
|
|
31
|
+
*/
|
|
32
|
+
_httpRequest(options, data) {
|
|
33
|
+
return new Promise((resolve, reject) => {
|
|
34
|
+
const req = https.request(options, (res) => {
|
|
35
|
+
let body = '';
|
|
36
|
+
res.on('data', (chunk) => body += chunk);
|
|
37
|
+
res.on('end', () => {
|
|
38
|
+
if (res.statusCode >= 200 && res.statusCode < 300) {
|
|
39
|
+
try {
|
|
40
|
+
resolve(JSON.parse(body));
|
|
41
|
+
} catch (e) {
|
|
42
|
+
resolve(body);
|
|
43
|
+
}
|
|
44
|
+
} else {
|
|
45
|
+
reject(new Error(`HTTP ${res.statusCode}: ${body}`));
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
req.on('error', reject);
|
|
50
|
+
if (data) req.write(JSON.stringify(data));
|
|
51
|
+
req.end();
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Send chat message
|
|
57
|
+
* @param {Object[]} messages - Chat messages
|
|
58
|
+
* @param {Object} options - Chat options
|
|
59
|
+
* @returns {Promise<Object>} - Response
|
|
60
|
+
*/
|
|
61
|
+
async chat(messages, options = {}) {
|
|
62
|
+
logger.info('Chat request', {
|
|
63
|
+
provider: this.provider,
|
|
64
|
+
model: this.model,
|
|
65
|
+
messageCount: messages.length
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
switch (this.provider) {
|
|
69
|
+
case 'anthropic':
|
|
70
|
+
return this._chatAnthropic(messages, options);
|
|
71
|
+
case 'moonshot':
|
|
72
|
+
return this._chatMoonshot(messages, options);
|
|
73
|
+
case 'alibaba':
|
|
74
|
+
case 'qwen':
|
|
75
|
+
return this._chatQwen(messages, options);
|
|
76
|
+
case 'openai':
|
|
77
|
+
return this._chatOpenAI(messages, options);
|
|
78
|
+
default:
|
|
79
|
+
throw new Error(`Unsupported provider: ${this.provider}`);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Anthropic Claude API
|
|
85
|
+
*/
|
|
86
|
+
async _chatAnthropic(messages, options) {
|
|
87
|
+
// Anthropic usually requires their SDK or complex headers
|
|
88
|
+
logger.debug('Anthropic chat', { model: this.model });
|
|
89
|
+
return {
|
|
90
|
+
content: '[Anthropic response placeholder - requires SDK]',
|
|
91
|
+
provider: 'anthropic',
|
|
92
|
+
model: this.model
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Moonshot (Kimi) API
|
|
98
|
+
*/
|
|
99
|
+
async _chatMoonshot(messages, options) {
|
|
100
|
+
const modelName = this.model === 'sonnet' ? 'moonshot-v1-8k' : this.model;
|
|
101
|
+
const data = {
|
|
102
|
+
model: modelName,
|
|
103
|
+
messages: messages,
|
|
104
|
+
temperature: options.temperature || 0.3
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
const reqOptions = {
|
|
108
|
+
hostname: 'api.moonshot.cn',
|
|
109
|
+
path: '/v1/chat/completions',
|
|
110
|
+
method: 'POST',
|
|
111
|
+
headers: {
|
|
112
|
+
'Content-Type': 'application/json',
|
|
113
|
+
'Authorization': `Bearer ${this.apiKey}`
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
try {
|
|
118
|
+
const response = await this._httpRequest(reqOptions, data);
|
|
119
|
+
return {
|
|
120
|
+
content: response.choices[0].message.content,
|
|
121
|
+
provider: 'moonshot',
|
|
122
|
+
model: modelName
|
|
123
|
+
};
|
|
124
|
+
} catch (error) {
|
|
125
|
+
logger.error('Moonshot API error', { error: error.message });
|
|
126
|
+
throw error;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Alibaba Qwen API (DashScope)
|
|
132
|
+
*/
|
|
133
|
+
async _chatQwen(messages, options) {
|
|
134
|
+
// Map generic model names to Qwen specific ones
|
|
135
|
+
let modelName = this.model;
|
|
136
|
+
if (modelName === 'sonnet' || modelName === 'gpt-4') modelName = 'qwen-max';
|
|
137
|
+
if (modelName === 'haiku' || modelName === 'gpt-3.5-turbo') modelName = 'qwen-plus';
|
|
138
|
+
|
|
139
|
+
const data = {
|
|
140
|
+
model: modelName,
|
|
141
|
+
input: {
|
|
142
|
+
messages: messages
|
|
143
|
+
},
|
|
144
|
+
parameters: {
|
|
145
|
+
result_format: 'message',
|
|
146
|
+
temperature: options.temperature || 0.3
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
const reqOptions = {
|
|
151
|
+
hostname: 'dashscope.aliyuncs.com',
|
|
152
|
+
path: '/api/v1/services/aigc/text-generation/generation',
|
|
153
|
+
method: 'POST',
|
|
154
|
+
headers: {
|
|
155
|
+
'Content-Type': 'application/json',
|
|
156
|
+
'Authorization': `Bearer ${this.apiKey}`
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
try {
|
|
161
|
+
const response = await this._httpRequest(reqOptions, data);
|
|
162
|
+
return {
|
|
163
|
+
content: response.output.choices[0].message.content,
|
|
164
|
+
provider: 'alibaba',
|
|
165
|
+
model: modelName
|
|
166
|
+
};
|
|
167
|
+
} catch (error) {
|
|
168
|
+
logger.error('Qwen API error', { error: error.message });
|
|
169
|
+
throw error;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* OpenAI API
|
|
175
|
+
*/
|
|
176
|
+
async _chatOpenAI(messages, options) {
|
|
177
|
+
const modelName = this.model === 'sonnet' ? 'gpt-4-turbo' : this.model;
|
|
178
|
+
const data = {
|
|
179
|
+
model: modelName,
|
|
180
|
+
messages: messages,
|
|
181
|
+
temperature: options.temperature || 0.3
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
const reqOptions = {
|
|
185
|
+
hostname: 'api.openai.com',
|
|
186
|
+
path: '/v1/chat/completions',
|
|
187
|
+
method: 'POST',
|
|
188
|
+
headers: {
|
|
189
|
+
'Content-Type': 'application/json',
|
|
190
|
+
'Authorization': `Bearer ${this.apiKey}`
|
|
191
|
+
}
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
try {
|
|
195
|
+
const response = await this._httpRequest(reqOptions, data);
|
|
196
|
+
return {
|
|
197
|
+
content: response.choices[0].message.content,
|
|
198
|
+
provider: 'openai',
|
|
199
|
+
model: modelName
|
|
200
|
+
};
|
|
201
|
+
} catch (error) {
|
|
202
|
+
logger.error('OpenAI API error', { error: error.message });
|
|
203
|
+
throw error;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Count tokens (approximate)
|
|
209
|
+
* @param {string} text - Text to count
|
|
210
|
+
* @returns {number} - Approximate token count
|
|
211
|
+
*/
|
|
212
|
+
countTokens(text) {
|
|
213
|
+
return Math.ceil(text.length / 4);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Get provider info
|
|
218
|
+
* @returns {Object} - Provider information
|
|
219
|
+
*/
|
|
220
|
+
getInfo() {
|
|
221
|
+
return {
|
|
222
|
+
provider: this.provider,
|
|
223
|
+
model: this.model,
|
|
224
|
+
hasApiKey: !!this.apiKey
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Create provider from config
|
|
231
|
+
* @param {Object} config - Provider config
|
|
232
|
+
* @returns {ModelProvider} - Model provider instance
|
|
233
|
+
*/
|
|
234
|
+
function createProvider(config) {
|
|
235
|
+
return new ModelProvider(config);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
module.exports = {
|
|
239
|
+
ModelProvider,
|
|
240
|
+
createProvider
|
|
241
|
+
};
|