polydev-ai 1.8.23 → 1.8.25
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/mcp/stdio-wrapper.js +109 -45
- package/package.json +1 -1
package/mcp/stdio-wrapper.js
CHANGED
|
@@ -234,6 +234,9 @@ class StdioMCPWrapper {
|
|
|
234
234
|
process.exit(1);
|
|
235
235
|
}
|
|
236
236
|
|
|
237
|
+
// Server URL for API calls
|
|
238
|
+
this.serverUrl = 'https://www.polydev.ai/api/mcp';
|
|
239
|
+
|
|
237
240
|
// Initialize CLI Manager for local CLI functionality
|
|
238
241
|
this.cliManager = new CLIManager();
|
|
239
242
|
|
|
@@ -296,7 +299,7 @@ class StdioMCPWrapper {
|
|
|
296
299
|
// Handle get_perspectives with local CLIs + remote perspectives
|
|
297
300
|
const toolName = params.name;
|
|
298
301
|
|
|
299
|
-
if (toolName === 'get_perspectives') {
|
|
302
|
+
if (toolName === 'get_perspectives' || toolName === 'polydev.get_perspectives') {
|
|
300
303
|
return await this.handleGetPerspectivesWithCLIs(params, id);
|
|
301
304
|
}
|
|
302
305
|
|
|
@@ -566,6 +569,7 @@ class StdioMCPWrapper {
|
|
|
566
569
|
/**
|
|
567
570
|
* Local CLI prompt sending with ALL available CLIs + remote perspectives
|
|
568
571
|
* Respects user's perspectives_per_message setting for total perspectives
|
|
572
|
+
* Uses allProviders from dashboard - tries CLI first, falls back to API
|
|
569
573
|
*/
|
|
570
574
|
async localSendCliPrompt(args) {
|
|
571
575
|
console.error(`[Stdio Wrapper] Local CLI prompt sending with perspectives`);
|
|
@@ -587,7 +591,7 @@ class StdioMCPWrapper {
|
|
|
587
591
|
const gracefulTimeout = Math.min(timeout_ms, 600000);
|
|
588
592
|
|
|
589
593
|
// Fetch user's model preferences (cached, non-blocking on failure)
|
|
590
|
-
// This also fetches perspectivesPerMessage setting
|
|
594
|
+
// This also fetches perspectivesPerMessage setting and allProviders list
|
|
591
595
|
let modelPreferences = {};
|
|
592
596
|
try {
|
|
593
597
|
modelPreferences = await this.fetchUserModelPreferences();
|
|
@@ -613,48 +617,85 @@ class StdioMCPWrapper {
|
|
|
613
617
|
const result = await this.cliManager.sendCliPrompt(provider_id, prompt, mode, gracefulTimeout, model);
|
|
614
618
|
localResults = [{ provider_id, ...result }];
|
|
615
619
|
} else {
|
|
616
|
-
// No specific provider - use
|
|
617
|
-
//
|
|
618
|
-
console.error(`[Stdio Wrapper] Using
|
|
619
|
-
const { available: availableClis, unavailable: unavailableClis } = await this.getAllAvailableProviders();
|
|
620
|
-
|
|
621
|
-
// Build ordered list: use CLI if available, otherwise mark for API fallback
|
|
622
|
-
const userOrder = this.userProviderOrder || ['claude_code', 'codex_cli', 'gemini_cli'];
|
|
623
|
-
const providersToUse = userOrder.slice(0, maxPerspectives);
|
|
620
|
+
// No specific provider - use allProviders from dashboard in order
|
|
621
|
+
// For each provider: try CLI first if available, otherwise use API
|
|
622
|
+
console.error(`[Stdio Wrapper] Using allProviders from dashboard (max: ${maxPerspectives})`);
|
|
624
623
|
|
|
625
|
-
//
|
|
626
|
-
const
|
|
627
|
-
|
|
624
|
+
// Get available CLIs for checking
|
|
625
|
+
const { available: availableClis } = await this.getAllAvailableProviders();
|
|
626
|
+
console.error(`[Stdio Wrapper] Available CLIs: ${availableClis.join(', ') || 'none'}`);
|
|
628
627
|
|
|
629
|
-
|
|
628
|
+
// Use allProviders from API (full list including API-only providers)
|
|
629
|
+
// Falls back to CLI-only providers if allProviders not available
|
|
630
|
+
const allProviders = this.allProviders || [];
|
|
630
631
|
|
|
631
|
-
if (
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
632
|
+
if (allProviders.length === 0) {
|
|
633
|
+
// Fallback: use legacy CLI-only flow
|
|
634
|
+
console.error(`[Stdio Wrapper] No allProviders, using legacy CLI-only flow`);
|
|
635
|
+
const userOrder = this.userProviderOrder || ['claude_code', 'codex_cli', 'gemini_cli'];
|
|
636
|
+
const cliProviders = userOrder.slice(0, maxPerspectives).filter(p => availableClis.includes(p));
|
|
636
637
|
|
|
637
|
-
// Run all CLI prompts concurrently
|
|
638
638
|
const cliPromises = cliProviders.map(async (providerId) => {
|
|
639
639
|
try {
|
|
640
640
|
const model = modelPreferences[providerId] || null;
|
|
641
|
-
if (model) {
|
|
642
|
-
console.error(`[Stdio Wrapper] Using user's preferred model for ${providerId}: ${model}`);
|
|
643
|
-
}
|
|
644
641
|
const result = await this.cliManager.sendCliPrompt(providerId, prompt, mode, gracefulTimeout, model);
|
|
645
642
|
return { provider_id: providerId, ...result };
|
|
646
643
|
} catch (error) {
|
|
647
|
-
|
|
648
|
-
return {
|
|
649
|
-
provider_id: providerId,
|
|
650
|
-
success: false,
|
|
651
|
-
error: error.message,
|
|
652
|
-
latency_ms: gracefulTimeout
|
|
653
|
-
};
|
|
644
|
+
return { provider_id: providerId, success: false, error: error.message };
|
|
654
645
|
}
|
|
655
646
|
});
|
|
656
|
-
|
|
657
647
|
localResults = await Promise.all(cliPromises);
|
|
648
|
+
} else {
|
|
649
|
+
// NEW: Use allProviders list (includes CLI + API-only providers)
|
|
650
|
+
const providersToUse = allProviders.slice(0, maxPerspectives);
|
|
651
|
+
console.error(`[Stdio Wrapper] Using ${providersToUse.length} providers from dashboard`);
|
|
652
|
+
|
|
653
|
+
// Separate into CLI providers vs API-only providers
|
|
654
|
+
const cliProviderEntries = [];
|
|
655
|
+
const apiOnlyProviders = [];
|
|
656
|
+
|
|
657
|
+
for (const p of providersToUse) {
|
|
658
|
+
if (p.cliId && availableClis.includes(p.cliId)) {
|
|
659
|
+
// Has CLI and CLI is available
|
|
660
|
+
cliProviderEntries.push(p);
|
|
661
|
+
} else {
|
|
662
|
+
// No CLI or CLI unavailable - needs API
|
|
663
|
+
apiOnlyProviders.push(p);
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
console.error(`[Stdio Wrapper] Provider breakdown: CLI=${cliProviderEntries.map(p => p.cliId).join(', ') || 'none'}, API-only=${apiOnlyProviders.map(p => p.provider).join(', ') || 'none'}`);
|
|
668
|
+
|
|
669
|
+
// Run all CLI prompts concurrently
|
|
670
|
+
if (cliProviderEntries.length > 0) {
|
|
671
|
+
const cliPromises = cliProviderEntries.map(async (providerEntry) => {
|
|
672
|
+
try {
|
|
673
|
+
const model = providerEntry.model || modelPreferences[providerEntry.cliId] || null;
|
|
674
|
+
if (model) {
|
|
675
|
+
console.error(`[Stdio Wrapper] Using model for ${providerEntry.cliId}: ${model}`);
|
|
676
|
+
}
|
|
677
|
+
const result = await this.cliManager.sendCliPrompt(providerEntry.cliId, prompt, mode, gracefulTimeout, model);
|
|
678
|
+
return {
|
|
679
|
+
provider_id: providerEntry.cliId,
|
|
680
|
+
original_provider: providerEntry.provider,
|
|
681
|
+
...result
|
|
682
|
+
};
|
|
683
|
+
} catch (error) {
|
|
684
|
+
console.error(`[Stdio Wrapper] CLI ${providerEntry.cliId} failed:`, error.message);
|
|
685
|
+
return {
|
|
686
|
+
provider_id: providerEntry.cliId,
|
|
687
|
+
original_provider: providerEntry.provider,
|
|
688
|
+
success: false,
|
|
689
|
+
error: error.message,
|
|
690
|
+
latency_ms: gracefulTimeout
|
|
691
|
+
};
|
|
692
|
+
}
|
|
693
|
+
});
|
|
694
|
+
localResults = await Promise.all(cliPromises);
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
// Store API-only providers info for remote API call
|
|
698
|
+
this._apiOnlyProviders = apiOnlyProviders;
|
|
658
699
|
}
|
|
659
700
|
}
|
|
660
701
|
|
|
@@ -665,15 +706,26 @@ class StdioMCPWrapper {
|
|
|
665
706
|
|
|
666
707
|
// Calculate how many successful local perspectives we got
|
|
667
708
|
const successfulLocalCount = localResults.filter(r => r.success).length;
|
|
668
|
-
const
|
|
709
|
+
const failedCliCount = localResults.filter(r => !r.success).length;
|
|
710
|
+
|
|
711
|
+
// Need API for: API-only providers + failed CLIs
|
|
712
|
+
const apiOnlyCount = (this._apiOnlyProviders || []).length;
|
|
713
|
+
const remainingPerspectives = apiOnlyCount + failedCliCount;
|
|
669
714
|
|
|
670
|
-
// Get remote perspectives only
|
|
715
|
+
// Get remote perspectives for API-only providers and failed CLIs
|
|
671
716
|
let perspectivesResult;
|
|
672
717
|
if (remainingPerspectives > 0) {
|
|
673
|
-
console.error(`[Stdio Wrapper] Need ${remainingPerspectives}
|
|
674
|
-
|
|
718
|
+
console.error(`[Stdio Wrapper] Need ${remainingPerspectives} perspectives from remote API (${apiOnlyCount} API-only + ${failedCliCount} failed CLIs)`);
|
|
719
|
+
|
|
720
|
+
// Pass API-only provider info to help remote API choose correct models
|
|
721
|
+
const apiProvidersInfo = (this._apiOnlyProviders || []).map(p => ({
|
|
722
|
+
provider: p.provider,
|
|
723
|
+
model: p.model
|
|
724
|
+
}));
|
|
725
|
+
|
|
726
|
+
perspectivesResult = await this.callPerspectivesForCli(args, localResults, remainingPerspectives, apiProvidersInfo);
|
|
675
727
|
} else {
|
|
676
|
-
console.error(`[Stdio Wrapper] Already have ${successfulLocalCount} perspectives, skipping remote call`);
|
|
728
|
+
console.error(`[Stdio Wrapper] Already have ${successfulLocalCount} perspectives from CLIs, skipping remote call`);
|
|
677
729
|
perspectivesResult = {
|
|
678
730
|
success: true,
|
|
679
731
|
content: '',
|
|
@@ -859,8 +911,9 @@ class StdioMCPWrapper {
|
|
|
859
911
|
* @param {Object} args - Original request arguments
|
|
860
912
|
* @param {Array} localResults - Results from local CLIs
|
|
861
913
|
* @param {number} maxPerspectives - Maximum number of remote perspectives to fetch
|
|
914
|
+
* @param {Array} apiProvidersInfo - Optional array of API-only providers to request (from allProviders)
|
|
862
915
|
*/
|
|
863
|
-
async callPerspectivesForCli(args, localResults, maxPerspectives = 2) {
|
|
916
|
+
async callPerspectivesForCli(args, localResults, maxPerspectives = 2, apiProvidersInfo = []) {
|
|
864
917
|
// Determine which providers succeeded locally
|
|
865
918
|
const successfulLocalProviders = localResults
|
|
866
919
|
.filter(r => r.success)
|
|
@@ -877,21 +930,25 @@ class StdioMCPWrapper {
|
|
|
877
930
|
.map(cli => cliToApiProvider[cli])
|
|
878
931
|
.filter(Boolean);
|
|
879
932
|
|
|
880
|
-
// If
|
|
881
|
-
if (maxPerspectives <= 0
|
|
882
|
-
|
|
883
|
-
(excludeProviders.includes('anthropic') && excludeProviders.includes('openai') && excludeProviders.includes('google'))) {
|
|
884
|
-
console.error(`[Stdio Wrapper] All providers covered by local CLIs or max perspectives reached, skipping remote perspectives`);
|
|
933
|
+
// If we don't need any perspectives, skip remote call
|
|
934
|
+
if (maxPerspectives <= 0) {
|
|
935
|
+
console.error(`[Stdio Wrapper] Max perspectives is 0, skipping remote perspectives`);
|
|
885
936
|
return {
|
|
886
937
|
success: true,
|
|
887
938
|
content: '',
|
|
888
939
|
skipped: true,
|
|
889
|
-
reason: '
|
|
940
|
+
reason: 'No perspectives needed',
|
|
890
941
|
timestamp: new Date().toISOString()
|
|
891
942
|
};
|
|
892
943
|
}
|
|
893
944
|
|
|
894
|
-
|
|
945
|
+
// Build list of specific providers to request (from API-only providers)
|
|
946
|
+
const requestProviders = apiProvidersInfo.map(p => ({
|
|
947
|
+
provider: p.provider,
|
|
948
|
+
model: p.model
|
|
949
|
+
}));
|
|
950
|
+
|
|
951
|
+
console.error(`[Stdio Wrapper] Calling remote perspectives (excluding: ${excludeProviders.join(', ') || 'none'}, requesting: ${requestProviders.map(p => p.provider).join(', ') || 'any'}, max: ${maxPerspectives})`);
|
|
895
952
|
|
|
896
953
|
// Format CLI responses for logging on the server
|
|
897
954
|
const cliResponses = localResults.map(result => ({
|
|
@@ -915,6 +972,8 @@ class StdioMCPWrapper {
|
|
|
915
972
|
user_token: this.userToken,
|
|
916
973
|
// Exclude providers that succeeded locally
|
|
917
974
|
exclude_providers: excludeProviders,
|
|
975
|
+
// NEW: Specific providers to request (from API-only list)
|
|
976
|
+
request_providers: requestProviders.length > 0 ? requestProviders : undefined,
|
|
918
977
|
// Pass CLI responses for dashboard logging
|
|
919
978
|
cli_responses: cliResponses,
|
|
920
979
|
// Limit remote perspectives to what we need
|
|
@@ -1387,7 +1446,7 @@ class StdioMCPWrapper {
|
|
|
1387
1446
|
/**
|
|
1388
1447
|
* Fetch user's model preferences from API keys
|
|
1389
1448
|
* Returns a map of CLI provider -> default_model
|
|
1390
|
-
* Also fetches and caches perspectivesPerMessage setting
|
|
1449
|
+
* Also fetches and caches perspectivesPerMessage setting and allProviders list
|
|
1391
1450
|
*/
|
|
1392
1451
|
async fetchUserModelPreferences() {
|
|
1393
1452
|
// Check cache first
|
|
@@ -1433,8 +1492,13 @@ class StdioMCPWrapper {
|
|
|
1433
1492
|
// IMPORTANT: This is cached alongside modelPreferences and restored when cache is used
|
|
1434
1493
|
this.userProviderOrder = result.providerOrder || ['claude_code', 'codex_cli', 'gemini_cli'];
|
|
1435
1494
|
|
|
1495
|
+
// NEW: Cache full list of all providers (CLI + API-only) from dashboard
|
|
1496
|
+
// Format: [{ provider: 'openai', model: 'gpt-52-codex', cliId: 'codex_cli' }, { provider: 'x-ai', model: 'grok-4', cliId: null }, ...]
|
|
1497
|
+
this.allProviders = result.allProviders || [];
|
|
1498
|
+
|
|
1436
1499
|
console.error('[Stdio Wrapper] Model preferences loaded:', JSON.stringify(result.modelPreferences));
|
|
1437
1500
|
console.error('[Stdio Wrapper] Provider order:', JSON.stringify(this.userProviderOrder));
|
|
1501
|
+
console.error('[Stdio Wrapper] All providers:', JSON.stringify(this.allProviders));
|
|
1438
1502
|
console.error('[Stdio Wrapper] Perspectives per message:', this.perspectivesPerMessage);
|
|
1439
1503
|
return result.modelPreferences;
|
|
1440
1504
|
} else {
|
package/package.json
CHANGED