polydev-ai 1.6.0 → 1.7.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/lib/cliManager.js +75 -24
- package/mcp/stdio-wrapper.js +106 -2
- package/package.json +1 -1
package/lib/cliManager.js
CHANGED
|
@@ -42,9 +42,6 @@ class CLIManager {
|
|
|
42
42
|
id: 'claude_code',
|
|
43
43
|
name: 'Claude Code',
|
|
44
44
|
command: process.env.CLAUDE_CODE_PATH || 'claude',
|
|
45
|
-
// Model configuration: use env var or default to 'haiku' for speed
|
|
46
|
-
// Options: haiku (fastest), sonnet (balanced), opus (most capable)
|
|
47
|
-
model: process.env.POLYDEV_CLAUDE_MODEL || 'haiku',
|
|
48
45
|
subcommands: {
|
|
49
46
|
chat: [],
|
|
50
47
|
version: ['--version'],
|
|
@@ -58,9 +55,6 @@ class CLIManager {
|
|
|
58
55
|
id: 'codex_cli',
|
|
59
56
|
name: 'Codex CLI',
|
|
60
57
|
command: process.env.CODEX_CLI_PATH || 'codex',
|
|
61
|
-
// Model configuration: use env var or default to 'gpt-4o-mini' for speed
|
|
62
|
-
// Options: gpt-4o-mini (fastest), gpt-4o, o3-mini, o1, etc.
|
|
63
|
-
model: process.env.POLYDEV_CODEX_MODEL || 'gpt-4o-mini',
|
|
64
58
|
subcommands: {
|
|
65
59
|
chat: ['chat'],
|
|
66
60
|
version: ['--version'],
|
|
@@ -78,8 +72,6 @@ class CLIManager {
|
|
|
78
72
|
id: 'gemini_cli',
|
|
79
73
|
name: 'Gemini CLI',
|
|
80
74
|
command: process.env.GEMINI_CLI_PATH || 'gemini',
|
|
81
|
-
// Model configuration for Gemini
|
|
82
|
-
model: process.env.POLYDEV_GEMINI_MODEL || 'gemini-2.0-flash',
|
|
83
75
|
subcommands: {
|
|
84
76
|
chat: ['chat'],
|
|
85
77
|
version: ['--version'],
|
|
@@ -386,7 +378,7 @@ This is a known issue with @google/gemini-cli@0.3.4 and older Node.js versions.`
|
|
|
386
378
|
}
|
|
387
379
|
}
|
|
388
380
|
|
|
389
|
-
async sendCliPrompt(providerId, prompt, mode = 'args', timeoutMs = null) {
|
|
381
|
+
async sendCliPrompt(providerId, prompt, mode = 'args', timeoutMs = null, model = null) {
|
|
390
382
|
// Set provider-specific default timeouts (180s for all by default, complex prompts take time)
|
|
391
383
|
if (timeoutMs === null) {
|
|
392
384
|
timeoutMs = 180000; // 180 seconds default for all providers
|
|
@@ -432,6 +424,13 @@ This is a known issue with @google/gemini-cli@0.3.4 and older Node.js versions.`
|
|
|
432
424
|
};
|
|
433
425
|
}
|
|
434
426
|
|
|
427
|
+
// Log model being used
|
|
428
|
+
if (model) {
|
|
429
|
+
console.log(`[Polydev CLI] Using model for ${providerId}: ${model}`);
|
|
430
|
+
} else {
|
|
431
|
+
console.log(`[Polydev CLI] No model specified for ${providerId}, using CLI default`);
|
|
432
|
+
}
|
|
433
|
+
|
|
435
434
|
const promptVariants = [
|
|
436
435
|
provider.subcommands?.test_prompt ? [...provider.subcommands.test_prompt] : []
|
|
437
436
|
];
|
|
@@ -445,16 +444,15 @@ This is a known issue with @google/gemini-cli@0.3.4 and older Node.js versions.`
|
|
|
445
444
|
if (providerId === 'codex_cli') {
|
|
446
445
|
const execArgs = promptVariants.find(args => args.includes('exec')) || promptVariants[0];
|
|
447
446
|
try {
|
|
448
|
-
|
|
449
|
-
const content = await this.executeCodexExec(provider.command, execArgs, prompt, timeoutMs, provider.model);
|
|
447
|
+
const content = await this.executeCodexExec(provider.command, execArgs, prompt, timeoutMs, model);
|
|
450
448
|
return {
|
|
451
449
|
success: true,
|
|
452
450
|
content,
|
|
453
451
|
tokens_used: this.estimateTokens(prompt + content),
|
|
454
452
|
latency_ms: Date.now() - startTime,
|
|
455
453
|
provider: providerId,
|
|
456
|
-
model: provider.model,
|
|
457
454
|
mode: 'args',
|
|
455
|
+
model_used: model || 'cli_default',
|
|
458
456
|
timestamp: new Date()
|
|
459
457
|
};
|
|
460
458
|
} catch (error) {
|
|
@@ -463,7 +461,6 @@ This is a known issue with @google/gemini-cli@0.3.4 and older Node.js versions.`
|
|
|
463
461
|
error: `CLI execution failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
464
462
|
latency_ms: Date.now() - startTime,
|
|
465
463
|
provider: providerId,
|
|
466
|
-
model: provider.model,
|
|
467
464
|
mode,
|
|
468
465
|
timestamp: new Date()
|
|
469
466
|
};
|
|
@@ -473,9 +470,25 @@ This is a known issue with @google/gemini-cli@0.3.4 and older Node.js versions.`
|
|
|
473
470
|
let lastErrorMessage = null;
|
|
474
471
|
|
|
475
472
|
for (const promptArgs of promptVariants) {
|
|
476
|
-
//
|
|
477
|
-
|
|
478
|
-
|
|
473
|
+
// Build args with model flag if specified
|
|
474
|
+
let args = Array.isArray(promptArgs) ? [...promptArgs] : [];
|
|
475
|
+
|
|
476
|
+
// Add model flag based on CLI type
|
|
477
|
+
if (model) {
|
|
478
|
+
if (providerId === 'claude_code') {
|
|
479
|
+
// Claude Code uses --model flag
|
|
480
|
+
args = ['--model', model, ...args, prompt];
|
|
481
|
+
} else if (providerId === 'gemini_cli') {
|
|
482
|
+
// Gemini CLI uses -m flag
|
|
483
|
+
args = ['-m', model, ...args, prompt];
|
|
484
|
+
} else {
|
|
485
|
+
// Default: just append prompt
|
|
486
|
+
args = [...args, prompt];
|
|
487
|
+
}
|
|
488
|
+
} else {
|
|
489
|
+
args = [...args, prompt];
|
|
490
|
+
}
|
|
491
|
+
|
|
479
492
|
try {
|
|
480
493
|
const result = await this.executeCliCommand(
|
|
481
494
|
provider.command,
|
|
@@ -493,8 +506,8 @@ This is a known issue with @google/gemini-cli@0.3.4 and older Node.js versions.`
|
|
|
493
506
|
tokens_used: this.estimateTokens(prompt + content),
|
|
494
507
|
latency_ms: Date.now() - startTime,
|
|
495
508
|
provider: providerId,
|
|
496
|
-
model: provider.model,
|
|
497
509
|
mode: 'args',
|
|
510
|
+
model_used: model || 'cli_default',
|
|
498
511
|
timestamp: new Date()
|
|
499
512
|
};
|
|
500
513
|
}
|
|
@@ -502,6 +515,37 @@ This is a known issue with @google/gemini-cli@0.3.4 and older Node.js versions.`
|
|
|
502
515
|
lastErrorMessage = result.error;
|
|
503
516
|
} catch (error) {
|
|
504
517
|
lastErrorMessage = error instanceof Error ? error.message : String(error);
|
|
518
|
+
|
|
519
|
+
// If model was specified and command failed, retry without model (graceful fallback)
|
|
520
|
+
if (model && lastErrorMessage.includes('model')) {
|
|
521
|
+
console.log(`[Polydev CLI] Model ${model} may be invalid for ${providerId}, retrying without model flag`);
|
|
522
|
+
try {
|
|
523
|
+
const fallbackArgs = Array.isArray(promptArgs) ? [...promptArgs, prompt] : [prompt];
|
|
524
|
+
const fallbackResult = await this.executeCliCommand(
|
|
525
|
+
provider.command,
|
|
526
|
+
fallbackArgs,
|
|
527
|
+
'args',
|
|
528
|
+
timeoutMs,
|
|
529
|
+
undefined
|
|
530
|
+
);
|
|
531
|
+
|
|
532
|
+
if (!fallbackResult.error) {
|
|
533
|
+
const content = this.cleanCliResponse(fallbackResult.stdout || '');
|
|
534
|
+
return {
|
|
535
|
+
success: true,
|
|
536
|
+
content,
|
|
537
|
+
tokens_used: this.estimateTokens(prompt + content),
|
|
538
|
+
latency_ms: Date.now() - startTime,
|
|
539
|
+
provider: providerId,
|
|
540
|
+
mode: 'args',
|
|
541
|
+
model_used: 'cli_default_fallback',
|
|
542
|
+
timestamp: new Date()
|
|
543
|
+
};
|
|
544
|
+
}
|
|
545
|
+
} catch (fallbackError) {
|
|
546
|
+
// Fallback also failed, continue with original error
|
|
547
|
+
}
|
|
548
|
+
}
|
|
505
549
|
}
|
|
506
550
|
}
|
|
507
551
|
|
|
@@ -623,7 +667,7 @@ This is a known issue with @google/gemini-cli@0.3.4 and older Node.js versions.`
|
|
|
623
667
|
});
|
|
624
668
|
}
|
|
625
669
|
|
|
626
|
-
async executeCodexExec(executable, commandArgs, prompt, timeoutMs, model) {
|
|
670
|
+
async executeCodexExec(executable, commandArgs, prompt, timeoutMs, model = null) {
|
|
627
671
|
if (!executable) {
|
|
628
672
|
throw new Error('Missing Codex executable');
|
|
629
673
|
}
|
|
@@ -634,18 +678,25 @@ This is a known issue with @google/gemini-cli@0.3.4 and older Node.js versions.`
|
|
|
634
678
|
|
|
635
679
|
const workingDir = process.cwd();
|
|
636
680
|
|
|
637
|
-
// Build args with model
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
681
|
+
// Build args with optional model flag
|
|
682
|
+
// Codex CLI uses -m or --model flag
|
|
683
|
+
let args = [...commandArgs];
|
|
684
|
+
|
|
685
|
+
// Add model flag if specified
|
|
686
|
+
if (model) {
|
|
687
|
+
args.push('-m', model);
|
|
688
|
+
console.log(`[CLI Debug] Codex using model: ${model}`);
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
// Add standard flags and prompt
|
|
692
|
+
args.push(
|
|
642
693
|
'--sandbox',
|
|
643
694
|
'workspace-write',
|
|
644
695
|
'--skip-git-repo-check',
|
|
645
696
|
'--cd',
|
|
646
697
|
workingDir,
|
|
647
698
|
prompt
|
|
648
|
-
|
|
699
|
+
);
|
|
649
700
|
|
|
650
701
|
return new Promise((resolve, reject) => {
|
|
651
702
|
const baseTmp = process.env.POLYDEV_CLI_TMPDIR || process.env.TMPDIR || os.tmpdir();
|
package/mcp/stdio-wrapper.js
CHANGED
|
@@ -116,6 +116,11 @@ class StdioMCPWrapper {
|
|
|
116
116
|
|
|
117
117
|
// Smart refresh scheduler (will be started after initialization)
|
|
118
118
|
this.refreshScheduler = null;
|
|
119
|
+
|
|
120
|
+
// Cache for user model preferences (provider -> model)
|
|
121
|
+
this.userModelPreferences = null;
|
|
122
|
+
this.modelPreferencesCacheTime = null;
|
|
123
|
+
this.MODEL_PREFERENCES_CACHE_TTL = 5 * 60 * 1000; // 5 minutes cache
|
|
119
124
|
}
|
|
120
125
|
|
|
121
126
|
loadManifest() {
|
|
@@ -452,12 +457,26 @@ class StdioMCPWrapper {
|
|
|
452
457
|
// Use reasonable timeout for CLI responses (180 seconds for complex prompts)
|
|
453
458
|
const gracefulTimeout = Math.min(timeout_ms, 180000);
|
|
454
459
|
|
|
460
|
+
// Fetch user's model preferences (cached, non-blocking on failure)
|
|
461
|
+
let modelPreferences = {};
|
|
462
|
+
try {
|
|
463
|
+
modelPreferences = await this.fetchUserModelPreferences();
|
|
464
|
+
} catch (prefError) {
|
|
465
|
+
console.error('[Stdio Wrapper] Model preferences fetch failed (will use CLI defaults):', prefError.message);
|
|
466
|
+
}
|
|
467
|
+
|
|
455
468
|
let localResults = [];
|
|
456
469
|
|
|
457
470
|
if (provider_id) {
|
|
458
471
|
// Specific provider requested - use only that one
|
|
459
472
|
console.error(`[Stdio Wrapper] Using specific provider: ${provider_id}`);
|
|
460
|
-
const
|
|
473
|
+
const model = modelPreferences[provider_id] || null;
|
|
474
|
+
if (model) {
|
|
475
|
+
console.error(`[Stdio Wrapper] Using user's preferred model for ${provider_id}: ${model}`);
|
|
476
|
+
} else {
|
|
477
|
+
console.error(`[Stdio Wrapper] No model preference for ${provider_id}, using CLI default`);
|
|
478
|
+
}
|
|
479
|
+
const result = await this.cliManager.sendCliPrompt(provider_id, prompt, mode, gracefulTimeout, model);
|
|
461
480
|
localResults = [{ provider_id, ...result }];
|
|
462
481
|
} else {
|
|
463
482
|
// No specific provider - use ALL available local CLIs
|
|
@@ -473,7 +492,11 @@ class StdioMCPWrapper {
|
|
|
473
492
|
// Run all CLI prompts concurrently
|
|
474
493
|
const cliPromises = availableProviders.map(async (providerId) => {
|
|
475
494
|
try {
|
|
476
|
-
const
|
|
495
|
+
const model = modelPreferences[providerId] || null;
|
|
496
|
+
if (model) {
|
|
497
|
+
console.error(`[Stdio Wrapper] Using user's preferred model for ${providerId}: ${model}`);
|
|
498
|
+
}
|
|
499
|
+
const result = await this.cliManager.sendCliPrompt(providerId, prompt, mode, gracefulTimeout, model);
|
|
477
500
|
return { provider_id: providerId, ...result };
|
|
478
501
|
} catch (error) {
|
|
479
502
|
console.error(`[Stdio Wrapper] CLI ${providerId} failed:`, error.message);
|
|
@@ -1020,6 +1043,87 @@ class StdioMCPWrapper {
|
|
|
1020
1043
|
}
|
|
1021
1044
|
}
|
|
1022
1045
|
|
|
1046
|
+
/**
|
|
1047
|
+
* Fetch user's model preferences from API keys
|
|
1048
|
+
* Returns a map of CLI provider -> default_model
|
|
1049
|
+
*/
|
|
1050
|
+
async fetchUserModelPreferences() {
|
|
1051
|
+
// Check cache first
|
|
1052
|
+
if (this.userModelPreferences && this.modelPreferencesCacheTime) {
|
|
1053
|
+
const cacheAge = Date.now() - this.modelPreferencesCacheTime;
|
|
1054
|
+
if (cacheAge < this.MODEL_PREFERENCES_CACHE_TTL) {
|
|
1055
|
+
console.error('[Stdio Wrapper] Using cached model preferences');
|
|
1056
|
+
return this.userModelPreferences;
|
|
1057
|
+
}
|
|
1058
|
+
}
|
|
1059
|
+
|
|
1060
|
+
console.error('[Stdio Wrapper] Fetching user model preferences from API...');
|
|
1061
|
+
|
|
1062
|
+
try {
|
|
1063
|
+
// Call the dedicated model-preferences endpoint
|
|
1064
|
+
const response = await fetch('https://www.polydev.ai/api/model-preferences', {
|
|
1065
|
+
method: 'GET',
|
|
1066
|
+
headers: {
|
|
1067
|
+
'Authorization': `Bearer ${this.userToken}`,
|
|
1068
|
+
'User-Agent': 'polydev-stdio-wrapper/1.0.0'
|
|
1069
|
+
}
|
|
1070
|
+
});
|
|
1071
|
+
|
|
1072
|
+
if (!response.ok) {
|
|
1073
|
+
console.error('[Stdio Wrapper] Failed to fetch model preferences:', response.status);
|
|
1074
|
+
return this.userModelPreferences || {};
|
|
1075
|
+
}
|
|
1076
|
+
|
|
1077
|
+
const result = await response.json();
|
|
1078
|
+
|
|
1079
|
+
if (result.success && result.modelPreferences) {
|
|
1080
|
+
// Cache the preferences
|
|
1081
|
+
this.userModelPreferences = result.modelPreferences;
|
|
1082
|
+
this.modelPreferencesCacheTime = Date.now();
|
|
1083
|
+
|
|
1084
|
+
console.error('[Stdio Wrapper] Model preferences loaded:', JSON.stringify(result.modelPreferences));
|
|
1085
|
+
return result.modelPreferences;
|
|
1086
|
+
} else {
|
|
1087
|
+
console.error('[Stdio Wrapper] No model preferences in response');
|
|
1088
|
+
return this.userModelPreferences || {};
|
|
1089
|
+
}
|
|
1090
|
+
|
|
1091
|
+
} catch (error) {
|
|
1092
|
+
console.error('[Stdio Wrapper] Error fetching model preferences:', error.message);
|
|
1093
|
+
return this.userModelPreferences || {};
|
|
1094
|
+
}
|
|
1095
|
+
}
|
|
1096
|
+
|
|
1097
|
+
/**
|
|
1098
|
+
* Map provider name to CLI provider ID
|
|
1099
|
+
*/
|
|
1100
|
+
mapProviderToCli(provider) {
|
|
1101
|
+
const providerLower = (provider || '').toLowerCase().trim();
|
|
1102
|
+
|
|
1103
|
+
// Map provider names to CLI tool IDs
|
|
1104
|
+
const providerMap = {
|
|
1105
|
+
'anthropic': 'claude_code',
|
|
1106
|
+
'anthropic-ai': 'claude_code',
|
|
1107
|
+
'claude': 'claude_code',
|
|
1108
|
+
'openai': 'codex_cli',
|
|
1109
|
+
'open-ai': 'codex_cli',
|
|
1110
|
+
'gpt': 'codex_cli',
|
|
1111
|
+
'google': 'gemini_cli',
|
|
1112
|
+
'google-ai': 'gemini_cli',
|
|
1113
|
+
'gemini': 'gemini_cli'
|
|
1114
|
+
};
|
|
1115
|
+
|
|
1116
|
+
return providerMap[providerLower] || null;
|
|
1117
|
+
}
|
|
1118
|
+
|
|
1119
|
+
/**
|
|
1120
|
+
* Get model for a specific CLI provider
|
|
1121
|
+
*/
|
|
1122
|
+
async getModelForProvider(providerId) {
|
|
1123
|
+
const preferences = await this.fetchUserModelPreferences();
|
|
1124
|
+
return preferences[providerId] || null;
|
|
1125
|
+
}
|
|
1126
|
+
|
|
1023
1127
|
async start() {
|
|
1024
1128
|
console.log('Starting Polydev Stdio MCP Wrapper...');
|
|
1025
1129
|
|
package/package.json
CHANGED