vigthoria-cli 1.5.6 → 1.5.8
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/README.md +75 -0
- package/dist/commands/chat.d.ts +1 -0
- package/dist/commands/chat.d.ts.map +1 -1
- package/dist/commands/chat.js +161 -27
- package/dist/commands/chat.js.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/utils/api.d.ts +6 -5
- package/dist/utils/api.d.ts.map +1 -1
- package/dist/utils/api.js +51 -155
- package/dist/utils/api.js.map +1 -1
- package/dist/utils/config.d.ts +3 -0
- package/dist/utils/config.d.ts.map +1 -1
- package/dist/utils/config.js +31 -15
- package/dist/utils/config.js.map +1 -1
- package/dist/utils/files.d.ts.map +1 -1
- package/dist/utils/files.js +33 -0
- package/dist/utils/files.js.map +1 -1
- package/dist/utils/tools.d.ts.map +1 -1
- package/dist/utils/tools.js +100 -3
- package/dist/utils/tools.js.map +1 -1
- package/package.json +1 -1
- package/src/commands/chat.ts +169 -28
- package/src/index.ts +2 -1
- package/src/utils/api.ts +51 -161
- package/src/utils/config.ts +37 -25
- package/src/utils/files.ts +32 -0
- package/src/utils/tools.ts +98 -3
package/src/commands/chat.ts
CHANGED
|
@@ -66,21 +66,21 @@ export class ChatCommand {
|
|
|
66
66
|
const homeDir = process.env.HOME || process.env.USERPROFILE || '';
|
|
67
67
|
const isHomeDir = projectPath === homeDir || projectPath === homeDir.replace(/\\/g, '/');
|
|
68
68
|
if (isHomeDir && options.agent) {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
69
|
+
console.log('');
|
|
70
|
+
console.log(chalk.yellow('╔════════════════════════════════════════════════════════════╗'));
|
|
71
|
+
console.log(chalk.yellow('║') + chalk.yellow.bold(' ⚠ WARNING: Agent mode in home directory ') + chalk.yellow('║'));
|
|
72
|
+
console.log(chalk.yellow('╠════════════════════════════════════════════════════════════╣'));
|
|
73
|
+
console.log(chalk.yellow('║') + ' You are running agent mode in your home directory. ' + chalk.yellow('║'));
|
|
74
|
+
console.log(chalk.yellow('║') + ' The AI can access ALL files in this location. ' + chalk.yellow('║'));
|
|
75
|
+
console.log(chalk.yellow('║') + ' ' + chalk.yellow('║'));
|
|
76
|
+
console.log(chalk.yellow('║') + chalk.white(' For safety, navigate to your project folder first: ') + chalk.yellow('║'));
|
|
77
|
+
console.log(chalk.yellow('║') + chalk.cyan(' cd C:\\path\\to\\your\\project ') + chalk.yellow('║'));
|
|
78
|
+
console.log(chalk.yellow('║') + chalk.cyan(' vigthoria agent ') + chalk.yellow('║'));
|
|
79
|
+
console.log(chalk.yellow('║') + ' ' + chalk.yellow('║'));
|
|
80
|
+
console.log(chalk.yellow('║') + chalk.white(' Or specify a project path: ') + chalk.yellow('║'));
|
|
81
|
+
console.log(chalk.yellow('║') + chalk.cyan(' vigthoria agent -p C:\\path\\to\\your\\project ') + chalk.yellow('║'));
|
|
82
|
+
console.log(chalk.yellow('╚════════════════════════════════════════════════════════════╝'));
|
|
83
|
+
console.log('');
|
|
84
84
|
|
|
85
85
|
// Ask for confirmation
|
|
86
86
|
const readline = require('readline');
|
|
@@ -142,7 +142,16 @@ export class ChatCommand {
|
|
|
142
142
|
this.streamMode = options.stream !== false; // Default to true
|
|
143
143
|
this.localMode = false; // Never use local mode - always use Vigthoria API
|
|
144
144
|
|
|
145
|
+
// CRITICAL: Agent mode REQUIRES stronger models to prevent hallucinations
|
|
146
|
+
// Use Vigthoria Cloud for complex agent tasks
|
|
145
147
|
if (this.agentMode) {
|
|
148
|
+
// Upgrade model for agent mode if using a weak model
|
|
149
|
+
const weakModels = ['fast', 'mini', 'vigthoria-fast-1.7b'];
|
|
150
|
+
if (weakModels.includes(options.model)) {
|
|
151
|
+
this.logger.warn(`Agent mode works better with stronger models. Upgrading from '${options.model}' to 'code'`);
|
|
152
|
+
options.model = 'code';
|
|
153
|
+
}
|
|
154
|
+
|
|
146
155
|
this.tools = new AgenticTools(
|
|
147
156
|
this.logger,
|
|
148
157
|
projectPath, // Use resolved path
|
|
@@ -196,18 +205,35 @@ export class ChatCommand {
|
|
|
196
205
|
): string {
|
|
197
206
|
let prompt = `You are Vigthoria, the premier AI coding assistant of Vigthoria Technologies.
|
|
198
207
|
|
|
199
|
-
IDENTITY
|
|
200
|
-
- Created by Vigthoria Technologies
|
|
208
|
+
## IDENTITY & BRAND
|
|
209
|
+
- Created by Vigthoria Technologies (NOT OpenAI, NOT Anthropic, NOT Microsoft)
|
|
201
210
|
- Mascot: Viggy the Blue Queen
|
|
202
211
|
- Philosophy: "Innovation through Intelligence"
|
|
203
|
-
|
|
204
|
-
|
|
212
|
+
- Always respond as "Vigthoria" - never claim to be another AI
|
|
213
|
+
|
|
214
|
+
## VIGTHORIA ECOSYSTEM (Important - Know This!)
|
|
215
|
+
Vigthoria is a comprehensive tech platform with these key services:
|
|
216
|
+
- **Vigthoria Coder** (coder.vigthoria.io): AI-powered coding IDE and CLI (this tool!)
|
|
217
|
+
- **Vigthoria Community** (community.vigthoria.io): Code sharing platform, NOT GitHub. When user mentions "repo", assume Vigthoria Community unless they say "GitHub"
|
|
218
|
+
- **Vigthoria GoA** (agent.vigthoria.io): Graph of Agents - autonomous AI orchestration
|
|
219
|
+
- **Vigthoria Meet** (meet.vigthoria.io): Video conferencing platform
|
|
220
|
+
- **Vigthoria Pay**: Payment processing service
|
|
221
|
+
- **Vigthoria B2C Hub**: Business-to-consumer services
|
|
222
|
+
- **Model Router** (port 4009): Routes AI requests to optimal models
|
|
223
|
+
|
|
224
|
+
## CRITICAL RULES - NEVER VIOLATE:
|
|
225
|
+
1. **NEVER HALLUCINATE** - If you don't know something, say so. Don't make up file contents, directories, or project structures.
|
|
226
|
+
2. **NEVER ASSUME FILE CONTENTS** - If asked about a file, you MUST use read_file tool first. Do NOT guess what's in a file.
|
|
227
|
+
3. **NEVER CONFUSE PLATFORMS** - Vigthoria Community is NOT GitHub. Windows paths are NOT Unix paths.
|
|
228
|
+
4. **ALWAYS USE TOOLS** - In agent mode, USE the tools to read files, not your imagination.
|
|
229
|
+
|
|
230
|
+
## Project Context
|
|
205
231
|
- Type: ${projectContext.type}
|
|
206
232
|
- Root: ${options.project}
|
|
207
233
|
- Key files: ${projectContext.files.slice(0, 10).join(', ')}
|
|
208
234
|
${projectContext.type === 'node' ? `- Dependencies: ${Object.keys(projectContext.dependencies).slice(0, 15).join(', ')}` : ''}
|
|
209
235
|
|
|
210
|
-
CODE QUALITY STANDARDS (CRITICAL):
|
|
236
|
+
## CODE QUALITY STANDARDS (CRITICAL):
|
|
211
237
|
1. ALWAYS produce complete, production-ready code - no placeholders
|
|
212
238
|
2. When creating UI/HTML/CSS:
|
|
213
239
|
- Ensure proper color contrast (text readable against backgrounds)
|
|
@@ -219,12 +245,13 @@ CODE QUALITY STANDARDS (CRITICAL):
|
|
|
219
245
|
6. Use semantic HTML, accessible patterns
|
|
220
246
|
7. Show COMPLETE implementations
|
|
221
247
|
|
|
222
|
-
Guidelines:
|
|
248
|
+
## Guidelines:
|
|
223
249
|
- Provide working code first, explanations second
|
|
224
250
|
- Be concise but thorough
|
|
225
251
|
- Excellence is the standard - mediocrity is not acceptable
|
|
252
|
+
- If you need to see file contents, USE read_file FIRST before responding
|
|
226
253
|
|
|
227
|
-
Special Commands (user may use these):
|
|
254
|
+
## Special Commands (user may use these):
|
|
228
255
|
- /file <path> - Read and include a file in context
|
|
229
256
|
- /edit <path> - Switch to file editing mode
|
|
230
257
|
- /diff - Show pending changes
|
|
@@ -309,14 +336,44 @@ Special Commands (user may use these):
|
|
|
309
336
|
input: process.stdin,
|
|
310
337
|
output: process.stdout,
|
|
311
338
|
prompt: chalk.cyan('you › '),
|
|
339
|
+
terminal: true,
|
|
312
340
|
});
|
|
313
341
|
|
|
314
342
|
let currentModel = options.model;
|
|
315
343
|
let pendingChanges: { file: string; content: string } | null = null;
|
|
344
|
+
let isRunning = true;
|
|
345
|
+
|
|
346
|
+
// Handle unexpected close events
|
|
347
|
+
this.rl.on('close', () => {
|
|
348
|
+
if (isRunning) {
|
|
349
|
+
console.log(chalk.yellow('\n\n⚠ Session interrupted. Saving...'));
|
|
350
|
+
if (this.currentSession && this.messages.length > 1) {
|
|
351
|
+
this.sessionManager.save(this.currentSession);
|
|
352
|
+
console.log(chalk.gray(`Session saved: ${this.currentSession.id}`));
|
|
353
|
+
}
|
|
354
|
+
console.log(chalk.cyan('Run `vigthoria chat --resume` to continue.\n'));
|
|
355
|
+
isRunning = false;
|
|
356
|
+
}
|
|
357
|
+
});
|
|
358
|
+
|
|
359
|
+
// Handle SIGINT (Ctrl+C) gracefully
|
|
360
|
+
process.on('SIGINT', () => {
|
|
361
|
+
if (isRunning) {
|
|
362
|
+
isRunning = false;
|
|
363
|
+
console.log(chalk.yellow('\n\nExiting...'));
|
|
364
|
+
if (this.currentSession && this.messages.length > 1) {
|
|
365
|
+
this.sessionManager.save(this.currentSession);
|
|
366
|
+
console.log(chalk.gray(`Session saved: ${this.currentSession.id}`));
|
|
367
|
+
}
|
|
368
|
+
console.log(chalk.cyan('Goodbye! 👋\n'));
|
|
369
|
+
process.exit(0);
|
|
370
|
+
}
|
|
371
|
+
});
|
|
316
372
|
|
|
317
373
|
this.rl.prompt();
|
|
318
374
|
|
|
319
375
|
for await (const line of this.rl) {
|
|
376
|
+
if (!isRunning) break;
|
|
320
377
|
const input = line.trim();
|
|
321
378
|
|
|
322
379
|
if (!input) {
|
|
@@ -340,8 +397,24 @@ Special Commands (user may use these):
|
|
|
340
397
|
|
|
341
398
|
case 'model':
|
|
342
399
|
if (args[0]) {
|
|
343
|
-
|
|
344
|
-
|
|
400
|
+
const newModel = args[0];
|
|
401
|
+
currentModel = newModel;
|
|
402
|
+
|
|
403
|
+
// Show branded model name
|
|
404
|
+
const modelInfo = this.config.getAvailableModels().find(m => m.id === newModel);
|
|
405
|
+
const isCloud = this.config.isCloudModel(newModel);
|
|
406
|
+
|
|
407
|
+
if (isCloud) {
|
|
408
|
+
console.log();
|
|
409
|
+
console.log(chalk.magenta(' ☁️ Switched to: ') + chalk.magenta.bold(modelInfo?.name || 'Vigthoria Cloud'));
|
|
410
|
+
console.log(chalk.gray(' 671B cloud model - ideal for complex tasks'));
|
|
411
|
+
console.log();
|
|
412
|
+
} else {
|
|
413
|
+
console.log();
|
|
414
|
+
console.log(chalk.green(' 🏠 Switched to: ') + chalk.green.bold(modelInfo?.name || newModel));
|
|
415
|
+
console.log(chalk.gray(' Local model - fast, no API costs'));
|
|
416
|
+
console.log();
|
|
417
|
+
}
|
|
345
418
|
} else {
|
|
346
419
|
this.printModels();
|
|
347
420
|
}
|
|
@@ -521,6 +594,9 @@ Special Commands (user may use these):
|
|
|
521
594
|
}
|
|
522
595
|
|
|
523
596
|
// Regular chat message
|
|
597
|
+
// Check if we should suggest Cloud upgrade for complex tasks
|
|
598
|
+
this.suggestCloudUpgrade(currentModel, input);
|
|
599
|
+
|
|
524
600
|
await this.chat(input, currentModel);
|
|
525
601
|
|
|
526
602
|
// Save message to session
|
|
@@ -579,7 +655,22 @@ Special Commands (user may use these):
|
|
|
579
655
|
|
|
580
656
|
} catch (error) {
|
|
581
657
|
spinner.stop();
|
|
582
|
-
|
|
658
|
+
const errMsg = (error as Error).message || 'Unknown error';
|
|
659
|
+
|
|
660
|
+
// Check for specific error types
|
|
661
|
+
if (errMsg.includes('ECONNREFUSED') || errMsg.includes('ENOTFOUND')) {
|
|
662
|
+
this.logger.error('Connection failed: Unable to reach AI service');
|
|
663
|
+
console.log(chalk.gray(' Check your internet connection or try again later.'));
|
|
664
|
+
} else if (errMsg.includes('timeout') || errMsg.includes('ETIMEDOUT')) {
|
|
665
|
+
this.logger.error('Request timed out: AI service took too long to respond');
|
|
666
|
+
console.log(chalk.gray(' Try a shorter query or check service status.'));
|
|
667
|
+
} else if (errMsg.includes('401') || errMsg.includes('Unauthorized')) {
|
|
668
|
+
this.logger.error('Authentication failed: Your session may have expired');
|
|
669
|
+
console.log(chalk.gray(' Run `vigthoria login` to re-authenticate.'));
|
|
670
|
+
} else {
|
|
671
|
+
this.logger.error('Failed to get response:', errMsg);
|
|
672
|
+
}
|
|
673
|
+
|
|
583
674
|
// Remove failed user message
|
|
584
675
|
this.messages.pop();
|
|
585
676
|
}
|
|
@@ -876,10 +967,60 @@ Special Commands (user may use these):
|
|
|
876
967
|
const models = this.config.getAvailableModels();
|
|
877
968
|
|
|
878
969
|
console.log();
|
|
879
|
-
this.logger.section('
|
|
880
|
-
|
|
881
|
-
|
|
970
|
+
this.logger.section('═══ VIGTHORIA MODELS ═══');
|
|
971
|
+
console.log();
|
|
972
|
+
|
|
973
|
+
// Group by tier
|
|
974
|
+
const localModels = models.filter(m => m.tier === 'local');
|
|
975
|
+
const cloudModels = models.filter(m => m.tier === 'cloud');
|
|
976
|
+
|
|
977
|
+
console.log(chalk.green.bold(' 🏠 VIGTHORIA LOCAL (Self-hosted, fast, no API cost)'));
|
|
978
|
+
console.log(chalk.gray(' ─────────────────────────────────────────────────'));
|
|
979
|
+
localModels.forEach(m => {
|
|
980
|
+
const isDefault = m.id === 'code';
|
|
981
|
+
const marker = isDefault ? chalk.yellow(' ★ DEFAULT') : '';
|
|
982
|
+
console.log(chalk.cyan(' ' + m.id.padEnd(15)) + chalk.white(m.name.padEnd(25)) + chalk.gray(m.description) + marker);
|
|
882
983
|
});
|
|
984
|
+
|
|
985
|
+
if (cloudModels.length > 0) {
|
|
986
|
+
console.log();
|
|
987
|
+
console.log(chalk.magenta.bold(' ☁️ VIGTHORIA CLOUD (Premium, for complex tasks)'));
|
|
988
|
+
console.log(chalk.gray(' ─────────────────────────────────────────────────'));
|
|
989
|
+
cloudModels.forEach(m => {
|
|
990
|
+
console.log(chalk.cyan(' ' + m.id.padEnd(15)) + chalk.white(m.name.padEnd(25)) + chalk.gray(m.description));
|
|
991
|
+
});
|
|
992
|
+
console.log();
|
|
993
|
+
console.log(chalk.yellow(' 💡 Tip: Use /model cloud for complex multi-file tasks'));
|
|
994
|
+
} else {
|
|
995
|
+
console.log();
|
|
996
|
+
console.log(chalk.yellow(' 💡 Upgrade to Pro for Vigthoria Cloud (671B models)'));
|
|
997
|
+
}
|
|
883
998
|
console.log();
|
|
884
999
|
}
|
|
1000
|
+
|
|
1001
|
+
// Suggest Cloud upgrade for complex tasks
|
|
1002
|
+
private suggestCloudUpgrade(currentModel: string, prompt: string): boolean {
|
|
1003
|
+
// Don't suggest if already on cloud
|
|
1004
|
+
if (this.config.isCloudModel(currentModel)) {
|
|
1005
|
+
return false;
|
|
1006
|
+
}
|
|
1007
|
+
|
|
1008
|
+
// Check if task seems complex
|
|
1009
|
+
if (this.config.isComplexTask(prompt)) {
|
|
1010
|
+
console.log();
|
|
1011
|
+
console.log(chalk.yellow('╔══════════════════════════════════════════════════════════╗'));
|
|
1012
|
+
console.log(chalk.yellow('║') + chalk.white.bold(' 💡 This looks like a complex task! ') + chalk.yellow('║'));
|
|
1013
|
+
console.log(chalk.yellow('║') + chalk.gray(' Current: ') + chalk.cyan(currentModel.padEnd(43)) + chalk.yellow('║'));
|
|
1014
|
+
console.log(chalk.yellow('║') + chalk.gray(' Suggested: ') + chalk.magenta('Vigthoria Cloud (671B)'.padEnd(41)) + chalk.yellow('║'));
|
|
1015
|
+
console.log(chalk.yellow('║ ║'));
|
|
1016
|
+
console.log(chalk.yellow('║') + chalk.white(' Type ') + chalk.cyan('/model cloud') + chalk.white(' for better results on: ') + chalk.yellow('║'));
|
|
1017
|
+
console.log(chalk.yellow('║') + chalk.gray(' • Multi-file refactoring ') + chalk.yellow('║'));
|
|
1018
|
+
console.log(chalk.yellow('║') + chalk.gray(' • Architecture decisions ') + chalk.yellow('║'));
|
|
1019
|
+
console.log(chalk.yellow('║') + chalk.gray(' • Complex feature implementation ') + chalk.yellow('║'));
|
|
1020
|
+
console.log(chalk.yellow('╚══════════════════════════════════════════════════════════╝'));
|
|
1021
|
+
console.log();
|
|
1022
|
+
return true;
|
|
1023
|
+
}
|
|
1024
|
+
return false;
|
|
1025
|
+
}
|
|
885
1026
|
}
|
package/src/index.ts
CHANGED
|
@@ -157,11 +157,12 @@ async function main() {
|
|
|
157
157
|
});
|
|
158
158
|
|
|
159
159
|
// Agent command - Agentic mode (Vigthoria Autonomous)
|
|
160
|
+
// Uses Vigthoria v3 Code 30B or Vigthoria Cloud for complex tasks
|
|
160
161
|
program
|
|
161
162
|
.command('agent')
|
|
162
163
|
.alias('a')
|
|
163
164
|
.description('Start agentic mode - AI can read/write files, run commands')
|
|
164
|
-
.option('-m, --model <model>', 'Select AI model', 'code')
|
|
165
|
+
.option('-m, --model <model>', 'Select AI model (code, cloud, ultra)', 'code')
|
|
165
166
|
.option('-p, --project <path>', 'Set project context path', process.cwd())
|
|
166
167
|
.option('--auto-approve', 'Auto-approve all actions (dangerous!)', false)
|
|
167
168
|
.action(async (options) => {
|
package/src/utils/api.ts
CHANGED
|
@@ -73,7 +73,7 @@ export class APIClient {
|
|
|
73
73
|
httpsAgent,
|
|
74
74
|
headers: {
|
|
75
75
|
'Content-Type': 'application/json',
|
|
76
|
-
'User-Agent': `Vigthoria-CLI/${process.env.npm_package_version || '1.
|
|
76
|
+
'User-Agent': `Vigthoria-CLI/${process.env.npm_package_version || '1.5.7'}`,
|
|
77
77
|
},
|
|
78
78
|
});
|
|
79
79
|
|
|
@@ -84,7 +84,7 @@ export class APIClient {
|
|
|
84
84
|
httpsAgent,
|
|
85
85
|
headers: {
|
|
86
86
|
'Content-Type': 'application/json',
|
|
87
|
-
'User-Agent': `Vigthoria-CLI/${process.env.npm_package_version || '1.
|
|
87
|
+
'User-Agent': `Vigthoria-CLI/${process.env.npm_package_version || '1.5.7'}`,
|
|
88
88
|
},
|
|
89
89
|
});
|
|
90
90
|
|
|
@@ -231,18 +231,21 @@ export class APIClient {
|
|
|
231
231
|
}
|
|
232
232
|
|
|
233
233
|
/**
|
|
234
|
-
* Chat API -
|
|
234
|
+
* Chat API - SIMPLIFIED Architecture (NO Ollama!)
|
|
235
235
|
*
|
|
236
|
-
*
|
|
237
|
-
*
|
|
236
|
+
* 1. Vigthoria Cloud API (coder.vigthoria.io) - Primary for authenticated users
|
|
237
|
+
* 2. Vigthoria Inference Service (port 8010) - Native 30B model
|
|
238
|
+
* 3. Model Router (port 4009) - Routes to OpenRouter (Kimi K2.5, DeepSeek)
|
|
239
|
+
*
|
|
240
|
+
* NO OLLAMA FALLBACK - That causes hallucinations with small models!
|
|
238
241
|
*/
|
|
239
242
|
async chat(messages: ChatMessage[], model: string, useLocal: boolean = false): Promise<ChatResponse> {
|
|
240
243
|
const resolvedModel = this.resolveModelId(model);
|
|
241
244
|
|
|
242
|
-
//
|
|
243
|
-
if (
|
|
245
|
+
// STRATEGY 1: Vigthoria Cloud API (authenticated users)
|
|
246
|
+
if (this.config.isAuthenticated()) {
|
|
244
247
|
try {
|
|
245
|
-
this.logger.debug(`
|
|
248
|
+
this.logger.debug(`Vigthoria Cloud API: ${resolvedModel}`);
|
|
246
249
|
const response = await this.client.post('/api/ai/chat', {
|
|
247
250
|
messages,
|
|
248
251
|
model: resolvedModel,
|
|
@@ -258,118 +261,62 @@ export class APIClient {
|
|
|
258
261
|
usage: response.data.usage,
|
|
259
262
|
};
|
|
260
263
|
}
|
|
261
|
-
this.logger.debug(`Cloud API returned success=false
|
|
264
|
+
this.logger.debug(`Cloud API returned success=false`);
|
|
262
265
|
} catch (error: any) {
|
|
263
266
|
const errMsg = error.response?.data?.error || error.message || 'Unknown error';
|
|
264
|
-
|
|
265
|
-
|
|
267
|
+
this.logger.debug(`Vigthoria Cloud API failed: ${errMsg}`);
|
|
268
|
+
// Continue to fallback strategies
|
|
266
269
|
}
|
|
267
|
-
} else {
|
|
268
|
-
this.logger.debug(`Skipping cloud API - useLocal: ${useLocal}, isAuthenticated: ${this.config.isAuthenticated()}`);
|
|
269
270
|
}
|
|
270
271
|
|
|
271
|
-
//
|
|
272
|
+
// STRATEGY 2: Vigthoria Inference Service (port 8010) - Native 30B model
|
|
272
273
|
try {
|
|
274
|
+
this.logger.debug(`Trying Vigthoria Inference Service (8010): ${resolvedModel}`);
|
|
273
275
|
const response = await axios.post('http://localhost:8010/v1/chat/completions', {
|
|
274
276
|
model: resolvedModel,
|
|
275
277
|
messages,
|
|
276
278
|
max_tokens: this.config.get('preferences').maxTokens,
|
|
277
279
|
temperature: 0.7,
|
|
278
280
|
stream: false,
|
|
279
|
-
}, { timeout:
|
|
281
|
+
}, { timeout: 180000 }); // 3 min timeout for 30B model
|
|
280
282
|
|
|
281
283
|
if (response.data.choices && response.data.choices.length > 0) {
|
|
282
284
|
return {
|
|
283
|
-
id: response.data.id || `vigthoria-
|
|
285
|
+
id: response.data.id || `vigthoria-inference-${Date.now()}`,
|
|
284
286
|
message: response.data.choices[0].message?.content || response.data.choices[0].text,
|
|
285
287
|
model: response.data.model || model,
|
|
286
288
|
usage: response.data.usage,
|
|
287
289
|
};
|
|
288
290
|
}
|
|
289
291
|
} catch (error) {
|
|
290
|
-
this.logger.debug('Vigthoria Inference
|
|
292
|
+
this.logger.debug('Vigthoria Inference Service (8010) unavailable');
|
|
291
293
|
}
|
|
292
294
|
|
|
293
|
-
//
|
|
295
|
+
// STRATEGY 3: Model Router (port 4009) - Routes to OpenRouter (Kimi/DeepSeek)
|
|
294
296
|
try {
|
|
295
|
-
|
|
296
|
-
|
|
297
|
+
this.logger.debug(`Trying Model Router (4009): ${resolvedModel}`);
|
|
298
|
+
const response = await axios.post('http://localhost:4009/v1/chat/completions', {
|
|
297
299
|
model: resolvedModel,
|
|
298
|
-
|
|
300
|
+
messages,
|
|
301
|
+
max_tokens: this.config.get('preferences').maxTokens,
|
|
299
302
|
temperature: 0.7,
|
|
300
303
|
stream: false,
|
|
301
|
-
}, { timeout:
|
|
304
|
+
}, { timeout: 180000 });
|
|
302
305
|
|
|
303
|
-
if (response.data.
|
|
306
|
+
if (response.data.choices && response.data.choices.length > 0) {
|
|
304
307
|
return {
|
|
305
308
|
id: response.data.id || `router-${Date.now()}`,
|
|
306
|
-
message: response.data.
|
|
309
|
+
message: response.data.choices[0].message?.content || response.data.choices[0].text,
|
|
307
310
|
model: response.data.model || model,
|
|
308
311
|
usage: response.data.usage,
|
|
309
312
|
};
|
|
310
313
|
}
|
|
311
314
|
} catch (error) {
|
|
312
|
-
this.logger.debug('Model Router (4009)
|
|
315
|
+
this.logger.debug('Model Router (4009) unavailable');
|
|
313
316
|
}
|
|
314
317
|
|
|
315
|
-
//
|
|
316
|
-
|
|
317
|
-
const ollamaModel = this.resolveToOllamaModel(model);
|
|
318
|
-
const prompt = this.formatMessagesForOllama(messages);
|
|
319
|
-
|
|
320
|
-
const response = await axios.post('http://localhost:11434/api/generate', {
|
|
321
|
-
model: ollamaModel,
|
|
322
|
-
prompt,
|
|
323
|
-
stream: false,
|
|
324
|
-
}, { timeout: 120000 });
|
|
325
|
-
|
|
326
|
-
return {
|
|
327
|
-
id: `ollama-${Date.now()}`,
|
|
328
|
-
message: response.data.response,
|
|
329
|
-
model: ollamaModel,
|
|
330
|
-
usage: {
|
|
331
|
-
prompt_tokens: response.data.prompt_eval_count || 0,
|
|
332
|
-
completion_tokens: response.data.eval_count || 0,
|
|
333
|
-
total_tokens: (response.data.prompt_eval_count || 0) + (response.data.eval_count || 0),
|
|
334
|
-
},
|
|
335
|
-
};
|
|
336
|
-
} catch (error) {
|
|
337
|
-
this.logger.debug('Ollama failed...');
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
throw new Error('AI service unavailable. Please check your authentication with `vigthoria login` or try again later.');
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
// Map CLI model names to Ollama model names (for local/offline fallback)
|
|
344
|
-
// Vigthoria_v3_Code_30B runs on qwen3-coder base via Vigthoria Cloud
|
|
345
|
-
// Local users with Ollama can use the base model for offline work
|
|
346
|
-
private resolveToOllamaModel(model: string): string {
|
|
347
|
-
const ollamaMap: Record<string, string> = {
|
|
348
|
-
'fast': 'qwen3:0.6b',
|
|
349
|
-
'mini': 'smollm2:135m',
|
|
350
|
-
'code': 'qwen3-coder:latest', // Vigthoria_v3_Code_30B (cloud) / qwen3-coder (local fallback)
|
|
351
|
-
'balanced': 'phi3:mini',
|
|
352
|
-
'creative': 'gemma3:latest',
|
|
353
|
-
'vigthoria-fast-1.7b': 'qwen3:0.6b',
|
|
354
|
-
'vigthoria-mini-0.6b': 'smollm2:135m',
|
|
355
|
-
'vigthoria-v3-code-30b': 'qwen3-coder:latest', // Vigthoria_v3_Code_30B
|
|
356
|
-
'vigthoria-v2-code-8b': 'qwen3-coder:latest', // Legacy v2
|
|
357
|
-
'vigthoria-balanced-4b': 'phi3:mini',
|
|
358
|
-
'vigthoria-creative-9b-v4': 'gemma3:latest',
|
|
359
|
-
};
|
|
360
|
-
return ollamaMap[model] || model;
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
// Format messages for Ollama's generate API
|
|
364
|
-
private formatMessagesForOllama(messages: ChatMessage[]): string {
|
|
365
|
-
return messages
|
|
366
|
-
.filter(m => m.role !== 'system' || messages.indexOf(m) === 0)
|
|
367
|
-
.map(m => {
|
|
368
|
-
if (m.role === 'system') return `System: ${m.content}\n\n`;
|
|
369
|
-
if (m.role === 'user') return `User: ${m.content}\n`;
|
|
370
|
-
return `Assistant: ${m.content}\n`;
|
|
371
|
-
})
|
|
372
|
-
.join('') + 'Assistant:';
|
|
318
|
+
// NO OLLAMA FALLBACK! That causes hallucinations!
|
|
319
|
+
throw new Error('AI service unavailable. Please ensure Vigthoria services are running or login with `vigthoria login`.');
|
|
373
320
|
}
|
|
374
321
|
|
|
375
322
|
// Streaming chat
|
|
@@ -543,108 +490,51 @@ export class APIClient {
|
|
|
543
490
|
return response.data;
|
|
544
491
|
}
|
|
545
492
|
|
|
546
|
-
// Model resolution - maps
|
|
493
|
+
// Model resolution - maps Vigthoria model names to internal IDs
|
|
494
|
+
// INTERNAL USE ONLY - users see only Vigthoria branding
|
|
547
495
|
private resolveModelId(shortName: string): string {
|
|
548
496
|
const modelMap: Record<string, string> = {
|
|
549
497
|
// ═══════════════════════════════════════════════════════════════
|
|
550
|
-
//
|
|
498
|
+
// VIGTHORIA LOCAL - Self-hosted models
|
|
551
499
|
// ═══════════════════════════════════════════════════════════════
|
|
552
500
|
'fast': 'vigthoria-fast-1.7b',
|
|
553
|
-
'mini': 'vigthoria-
|
|
501
|
+
'mini': 'vigthoria-fast-1.7b',
|
|
554
502
|
'balanced': 'vigthoria-balanced-4b',
|
|
555
|
-
|
|
556
|
-
// Code Models - Current & Future Versions
|
|
557
|
-
'code': 'vigthoria-v2-code-8b',
|
|
558
|
-
'code-v2': 'vigthoria-v2-code-8b',
|
|
559
|
-
'code-v2-8b': 'vigthoria-v2-code-8b',
|
|
560
|
-
'code-v3': 'vigthoria-v3-code-8b', // Future
|
|
561
|
-
'code-v3-8b': 'vigthoria-v3-code-8b', // Future
|
|
562
|
-
'code-v3-32b': 'vigthoria-v3-code-32b', // Future large model
|
|
563
|
-
'code-v4': 'vigthoria-v4-code-8b', // Future
|
|
564
|
-
'code-32b': 'vigthoria-v3-code-32b', // Future large model alias
|
|
565
|
-
|
|
566
|
-
// Creative Models
|
|
567
503
|
'creative': 'vigthoria-creative-9b-v4',
|
|
568
|
-
'creative-v3': 'vigthoria-creative-9b-v3',
|
|
569
|
-
'creative-v4': 'vigthoria-creative-9b-v4',
|
|
570
|
-
|
|
571
|
-
// Music Model
|
|
572
|
-
'music': 'vigthoria-music-master-4b',
|
|
573
|
-
'music-master': 'vigthoria-music-master-4b',
|
|
574
504
|
|
|
575
|
-
//
|
|
576
|
-
'
|
|
577
|
-
'
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
'master': 'vigthoria_master:latest',
|
|
581
|
-
'c1': 'vigthoria_c1_m:latest',
|
|
582
|
-
'm1': 'vigthoria_m1_m:latest',
|
|
505
|
+
// Code Models - 30B is the default powerhouse
|
|
506
|
+
'code': 'qwen3-coder:latest', // Internal: qwen3-coder 30B
|
|
507
|
+
'code-30b': 'qwen3-coder:latest',
|
|
508
|
+
'code-8b': 'vigthoria-v2-code-8b',
|
|
509
|
+
'pro': 'qwen3-coder:latest',
|
|
583
510
|
|
|
584
511
|
// ═══════════════════════════════════════════════════════════════
|
|
585
|
-
//
|
|
512
|
+
// VIGTHORIA CLOUD - Premium cloud models (internal routing)
|
|
586
513
|
// ═══════════════════════════════════════════════════════════════
|
|
587
|
-
'
|
|
588
|
-
'
|
|
589
|
-
'
|
|
590
|
-
'
|
|
591
|
-
'deepseek-r1': 'deepseek-r1:8b',
|
|
592
|
-
'deepseek-r1-32b': 'deepseek-r1:32b',
|
|
593
|
-
'llama3': 'llama3:8b-instruct-q4_0',
|
|
594
|
-
'mixtral': 'mixtral:8x7b-instruct-v0.1-q4_K_M',
|
|
514
|
+
'cloud': 'deepseek-v3.1:671b-cloud',
|
|
515
|
+
'cloud-reason': 'moonshotai/kimi-k2.5',
|
|
516
|
+
'agent': 'deepseek-v3.1:671b-cloud',
|
|
517
|
+
'ultra': 'deepseek-v3.1:671b-cloud',
|
|
595
518
|
};
|
|
596
519
|
|
|
597
|
-
// If already a full model ID
|
|
598
|
-
if (shortName.includes('vigthoria') || shortName.includes('
|
|
599
|
-
// Check if it's a known short name first
|
|
520
|
+
// If already a full model ID, return as-is
|
|
521
|
+
if (shortName.includes('vigthoria') || shortName.includes('/') || shortName.includes(':')) {
|
|
600
522
|
if (modelMap[shortName]) {
|
|
601
523
|
return modelMap[shortName];
|
|
602
524
|
}
|
|
603
|
-
// Otherwise assume it's a direct model ID
|
|
604
525
|
return shortName;
|
|
605
526
|
}
|
|
606
527
|
|
|
607
|
-
return modelMap[shortName] ||
|
|
528
|
+
return modelMap[shortName] || 'qwen3-coder:latest'; // Default to 30B
|
|
608
529
|
}
|
|
609
530
|
|
|
610
|
-
// Health check
|
|
531
|
+
// Health check
|
|
611
532
|
async healthCheck(): Promise<boolean> {
|
|
612
|
-
const apiUrl = this.config.get('apiUrl') || 'https://coder.vigthoria.io';
|
|
613
|
-
|
|
614
533
|
try {
|
|
615
|
-
|
|
616
|
-
const response = await this.client.get('/api/health', {
|
|
617
|
-
timeout: 10000, // 10 second timeout for health check
|
|
618
|
-
});
|
|
534
|
+
const response = await this.client.get('/api/health', { timeout: 10000 });
|
|
619
535
|
return response.data?.status === 'ok' || response.data?.healthy === true;
|
|
620
|
-
} catch
|
|
621
|
-
|
|
622
|
-
try {
|
|
623
|
-
const fallback = await this.client.get('/health', {
|
|
624
|
-
timeout: 5000,
|
|
625
|
-
});
|
|
626
|
-
return fallback.data?.status === 'ok' || fallback.data?.healthy === true || fallback.status === 200;
|
|
627
|
-
} catch {
|
|
628
|
-
// Fallback 2: try native fetch (Node 18+ built-in, works better on Windows)
|
|
629
|
-
try {
|
|
630
|
-
const controller = new AbortController();
|
|
631
|
-
const timeoutId = setTimeout(() => controller.abort(), 5000);
|
|
632
|
-
|
|
633
|
-
const fetchResponse = await fetch(`${apiUrl}/health`, {
|
|
634
|
-
method: 'GET',
|
|
635
|
-
signal: controller.signal,
|
|
636
|
-
});
|
|
637
|
-
clearTimeout(timeoutId);
|
|
638
|
-
|
|
639
|
-
if (fetchResponse.ok) {
|
|
640
|
-
const data = await fetchResponse.json() as { status?: string; healthy?: boolean };
|
|
641
|
-
return data?.status === 'ok' || data?.healthy === true;
|
|
642
|
-
}
|
|
643
|
-
return fetchResponse.ok;
|
|
644
|
-
} catch {
|
|
645
|
-
return false;
|
|
646
|
-
}
|
|
647
|
-
}
|
|
536
|
+
} catch {
|
|
537
|
+
return false;
|
|
648
538
|
}
|
|
649
539
|
}
|
|
650
540
|
}
|