hedgequantx 2.6.99 → 2.6.101

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hedgequantx",
3
- "version": "2.6.99",
3
+ "version": "2.6.101",
4
4
  "description": "HedgeQuantX - Prop Futures Trading CLI",
5
5
  "main": "src/app.js",
6
6
  "bin": {
@@ -892,25 +892,39 @@ const setupRemoteOAuth = async (provider, config) => {
892
892
  };
893
893
 
894
894
  // Try to fetch models with the new token
895
- spinner.text = 'Fetching available models...';
895
+ spinner.text = 'Fetching available models from API...';
896
896
  spinner.start();
897
897
 
898
898
  let models = [];
899
+ let fetchError = null;
899
900
  try {
900
901
  const { fetchModelsWithOAuth } = require('../services/ai/client');
901
902
  models = await fetchModelsWithOAuth(provider.id, result.access);
902
903
  } catch (e) {
903
- // Ignore - will use defaults
904
+ fetchError = e.message;
904
905
  }
905
906
 
906
- // Use defaults if API doesn't return models
907
+ // RULE: Models MUST come from API - no hardcoded fallback
907
908
  if (!models || models.length === 0) {
908
- models = getDefaultModelsForProvider(provider.id);
909
+ spinner.fail('Could not fetch models from API');
910
+ console.log();
911
+ console.log(chalk.red(' ERROR: Unable to retrieve models from provider API'));
912
+ console.log(chalk.white(' Possible causes:'));
913
+ console.log(chalk.gray(' - OAuth token may not have permission to list models'));
914
+ console.log(chalk.gray(' - Network issue or API temporarily unavailable'));
915
+ console.log(chalk.gray(' - Provider API may have changed'));
916
+ if (fetchError) {
917
+ console.log(chalk.gray(` - Error: ${fetchError}`));
918
+ }
919
+ console.log();
920
+ console.log(chalk.yellow(' Please try again or use API Key authentication instead.'));
921
+ await prompts.waitForEnter();
922
+ return await selectProviderOption(provider);
909
923
  }
910
924
 
911
925
  spinner.succeed(`Found ${models.length} models`);
912
926
 
913
- // Let user select model
927
+ // Let user select model from list
914
928
  const selectedModel = await selectModelFromList(models, config.name);
915
929
  if (!selectedModel) {
916
930
  return await selectProviderOption(provider);
@@ -931,35 +945,7 @@ const setupRemoteOAuth = async (provider, config) => {
931
945
  return await aiAgentMenu();
932
946
  };
933
947
 
934
- /**
935
- * Get default models for a provider (used when we can't query the API)
936
- */
937
- const getDefaultModelsForProvider = (providerId) => {
938
- // These are fetched from provider APIs - not hardcoded fallbacks
939
- // They represent the known model IDs that the provider supports
940
- const models = {
941
- anthropic: [
942
- 'claude-sonnet-4-20250514',
943
- 'claude-opus-4-20250514',
944
- 'claude-3-5-sonnet-20241022',
945
- 'claude-3-5-haiku-20241022',
946
- 'claude-3-opus-20240229'
947
- ],
948
- openai: [
949
- 'gpt-4o',
950
- 'gpt-4o-mini',
951
- 'gpt-4-turbo',
952
- 'o1-preview',
953
- 'o1-mini'
954
- ],
955
- gemini: [
956
- 'gemini-2.0-flash-exp',
957
- 'gemini-1.5-pro',
958
- 'gemini-1.5-flash'
959
- ]
960
- };
961
- return models[providerId] || [];
962
- };
948
+ // NOTE: promptForModelName was removed - models MUST come from API (RULES.md)
963
949
 
964
950
  /**
965
951
  * Setup OAuth via Manual Code Entry (unified flow for local and VPS)
@@ -1256,7 +1242,7 @@ const setupDeviceFlowOAuth = async (provider, config) => {
1256
1242
  return await selectProviderOption(provider);
1257
1243
  }
1258
1244
 
1259
- pollSpinner.text = 'FETCHING AVAILABLE MODELS...';
1245
+ pollSpinner.text = 'FETCHING AVAILABLE MODELS FROM API...';
1260
1246
 
1261
1247
  // Store OAuth credentials
1262
1248
  const credentials = {
@@ -1268,13 +1254,36 @@ const setupDeviceFlowOAuth = async (provider, config) => {
1268
1254
  }
1269
1255
  };
1270
1256
 
1271
- // Default models for Qwen
1272
- const defaultModels = ['qwen3-coder-plus', 'qwen3-235b', 'qwen-max', 'qwen-plus', 'qwen-turbo'];
1257
+ // Fetch models from API - NO hardcoded fallback (RULES.md)
1258
+ let models = [];
1259
+ let fetchError = null;
1260
+ try {
1261
+ const { fetchModelsWithOAuth } = require('../services/ai/client');
1262
+ models = await fetchModelsWithOAuth(provider.id, pollResult.access);
1263
+ } catch (e) {
1264
+ fetchError = e.message;
1265
+ }
1266
+
1267
+ if (!models || models.length === 0) {
1268
+ pollSpinner.fail('Could not fetch models from API');
1269
+ console.log();
1270
+ console.log(chalk.red(' ERROR: Unable to retrieve models from provider API'));
1271
+ console.log(chalk.white(' Possible causes:'));
1272
+ console.log(chalk.gray(' - OAuth token may not have permission to list models'));
1273
+ console.log(chalk.gray(' - Network issue or API temporarily unavailable'));
1274
+ if (fetchError) {
1275
+ console.log(chalk.gray(` - Error: ${fetchError}`));
1276
+ }
1277
+ console.log();
1278
+ console.log(chalk.yellow(' Please try again or use API Key authentication instead.'));
1279
+ await prompts.waitForEnter();
1280
+ return await selectProviderOption(provider);
1281
+ }
1273
1282
 
1274
- pollSpinner.succeed('AUTHENTICATION SUCCESSFUL');
1283
+ pollSpinner.succeed(`Found ${models.length} models`);
1275
1284
 
1276
- // Let user select model
1277
- const selectedModel = await selectModelFromList(defaultModels, config.name);
1285
+ // Let user select model from API list
1286
+ const selectedModel = await selectModelFromList(models, config.name);
1278
1287
  if (!selectedModel) {
1279
1288
  return await selectProviderOption(provider);
1280
1289
  }
@@ -525,15 +525,17 @@ const fetchAnthropicModels = async (apiKey) => {
525
525
 
526
526
  /**
527
527
  * Fetch available models from Anthropic API (OAuth auth)
528
+ *
528
529
  * @param {string} accessToken - OAuth access token
529
- * @returns {Promise<Array|null>} Array of model IDs or null on error
530
+ * @returns {Promise<Array|null>} Array of model IDs from API, null if unavailable
530
531
  *
531
532
  * Data source: https://api.anthropic.com/v1/models (GET with Bearer token)
533
+ * NO HARDCODED FALLBACK - models must come from API only
532
534
  */
533
535
  const fetchAnthropicModelsOAuth = async (accessToken) => {
534
536
  if (!accessToken) return null;
535
537
 
536
- const url = 'https://api.anthropic.com/v1/models';
538
+ const modelsUrl = 'https://api.anthropic.com/v1/models';
537
539
 
538
540
  const headers = {
539
541
  'Authorization': `Bearer ${accessToken}`,
@@ -542,14 +544,16 @@ const fetchAnthropicModelsOAuth = async (accessToken) => {
542
544
  };
543
545
 
544
546
  try {
545
- const response = await makeRequest(url, { method: 'GET', headers, timeout: 10000 });
547
+ const response = await makeRequest(modelsUrl, { method: 'GET', headers, timeout: 15000 });
546
548
  if (response.data && Array.isArray(response.data)) {
547
549
  const models = response.data.map(m => m.id).filter(Boolean);
548
550
  if (models.length > 0) return models;
549
551
  }
550
552
  return null;
551
553
  } catch (error) {
552
- // OAuth token may not support /models endpoint
554
+ if (process.env.HQX_DEBUG) {
555
+ console.error('[DEBUG] fetchAnthropicModelsOAuth error:', error.message);
556
+ }
553
557
  return null;
554
558
  }
555
559
  };
@@ -661,6 +665,7 @@ const fetchModelsWithOAuth = async (providerId, accessToken) => {
661
665
 
662
666
  case 'openai': {
663
667
  // Try OpenAI /v1/models endpoint with OAuth token
668
+ // NO HARDCODED FALLBACK - models must come from API only
664
669
  const openaiModels = await fetchOpenAIModels('https://api.openai.com/v1', accessToken);
665
670
  if (openaiModels && openaiModels.length > 0) {
666
671
  return openaiModels;
@@ -684,7 +689,9 @@ const fetchModelsWithOAuth = async (providerId, accessToken) => {
684
689
  .filter(Boolean);
685
690
  }
686
691
  } catch (e) {
687
- // ChatGPT backend not available
692
+ if (process.env.HQX_DEBUG) {
693
+ console.error('[DEBUG] ChatGPT backend error:', e.message);
694
+ }
688
695
  }
689
696
 
690
697
  return null;
@@ -692,21 +699,30 @@ const fetchModelsWithOAuth = async (providerId, accessToken) => {
692
699
 
693
700
  case 'gemini': {
694
701
  // Gemini OAuth - fetch from Generative Language API
695
- const geminiUrl = 'https://generativelanguage.googleapis.com/v1/models';
696
- const geminiHeaders = {
697
- 'Authorization': `Bearer ${accessToken}`
698
- };
699
- const geminiResponse = await makeRequest(geminiUrl, {
700
- method: 'GET',
701
- headers: geminiHeaders,
702
- timeout: 10000
703
- });
704
- if (geminiResponse.models && Array.isArray(geminiResponse.models)) {
705
- return geminiResponse.models
706
- .filter(m => m.supportedGenerationMethods?.includes('generateContent'))
707
- .map(m => m.name.replace('models/', ''))
708
- .filter(Boolean);
702
+ // NO HARDCODED FALLBACK - models must come from API only
703
+ try {
704
+ const geminiUrl = 'https://generativelanguage.googleapis.com/v1/models';
705
+ const geminiHeaders = {
706
+ 'Authorization': `Bearer ${accessToken}`
707
+ };
708
+ const geminiResponse = await makeRequest(geminiUrl, {
709
+ method: 'GET',
710
+ headers: geminiHeaders,
711
+ timeout: 15000
712
+ });
713
+ if (geminiResponse.models && Array.isArray(geminiResponse.models)) {
714
+ const models = geminiResponse.models
715
+ .filter(m => m.supportedGenerationMethods?.includes('generateContent'))
716
+ .map(m => m.name.replace('models/', ''))
717
+ .filter(Boolean);
718
+ if (models.length > 0) return models;
719
+ }
720
+ } catch (e) {
721
+ if (process.env.HQX_DEBUG) {
722
+ console.error('[DEBUG] Gemini models API error:', e.message);
723
+ }
709
724
  }
725
+
710
726
  return null;
711
727
  }
712
728