hedgequantx 2.6.74 → 2.6.76
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 +1 -1
- package/src/menus/ai-agent.js +75 -20
- package/src/services/ai/client.js +42 -0
package/package.json
CHANGED
package/src/menus/ai-agent.js
CHANGED
|
@@ -858,13 +858,22 @@ const setupBrowserOAuth = async (provider, config) => {
|
|
|
858
858
|
} else {
|
|
859
859
|
console.log(makeLine(chalk.yellow('COULD NOT OPEN BROWSER (VPS/SSH?)')));
|
|
860
860
|
console.log(makeLine(''));
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
console.log(makeLine(chalk.white(
|
|
861
|
+
|
|
862
|
+
// Different instructions for different providers
|
|
863
|
+
if (provider.id === 'anthropic') {
|
|
864
|
+
console.log(makeLine(chalk.white('AFTER LOGGING IN, YOU WILL SEE A CODE')));
|
|
865
|
+
console.log(makeLine(chalk.white('COPY THE ENTIRE CODE AND PASTE IT BELOW')));
|
|
866
|
+
console.log(makeLine(''));
|
|
867
|
+
console.log(makeLine(chalk.white('THE CODE LOOKS LIKE: abc123...#xyz789...')));
|
|
868
|
+
} else {
|
|
869
|
+
// Gemini, OpenAI, iFlow redirect to localhost - need full URL
|
|
870
|
+
console.log(makeLine(chalk.white('AFTER LOGGING IN, YOU WILL SEE A BLANK PAGE')));
|
|
871
|
+
console.log(makeLine(chalk.white('THE URL WILL START WITH: localhost:...')));
|
|
866
872
|
console.log(makeLine(''));
|
|
873
|
+
console.log(makeLine(chalk.green('COPY THE ENTIRE URL FROM THE ADDRESS BAR')));
|
|
874
|
+
console.log(makeLine(chalk.white('AND PASTE IT BELOW')));
|
|
867
875
|
}
|
|
876
|
+
console.log(makeLine(''));
|
|
868
877
|
console.log(makeLine(chalk.white('TYPE < TO CANCEL')));
|
|
869
878
|
drawBoxFooter(boxWidth);
|
|
870
879
|
// Display URL outside the box for easy copy-paste (no line breaks)
|
|
@@ -875,24 +884,41 @@ const setupBrowserOAuth = async (provider, config) => {
|
|
|
875
884
|
console.log();
|
|
876
885
|
}
|
|
877
886
|
|
|
878
|
-
const
|
|
887
|
+
const promptText = provider.id === 'anthropic'
|
|
888
|
+
? 'PASTE AUTHORIZATION CODE:'
|
|
889
|
+
: 'PASTE FULL CALLBACK URL:';
|
|
890
|
+
|
|
891
|
+
const input = await prompts.textInput(chalk.cyan(promptText));
|
|
879
892
|
|
|
880
|
-
if (!
|
|
893
|
+
if (!input || input === '<') {
|
|
881
894
|
return await selectProviderOption(provider);
|
|
882
895
|
}
|
|
883
896
|
|
|
897
|
+
// Extract code from URL if user pasted full callback URL
|
|
898
|
+
let code = input.trim();
|
|
899
|
+
if (code.includes('code=')) {
|
|
900
|
+
try {
|
|
901
|
+
const urlObj = new URL(code.replace('localhost', 'http://localhost'));
|
|
902
|
+
code = urlObj.searchParams.get('code') || code;
|
|
903
|
+
} catch (e) {
|
|
904
|
+
// Try regex extraction as fallback
|
|
905
|
+
const match = code.match(/[?&]code=([^&]+)/);
|
|
906
|
+
if (match) code = match[1];
|
|
907
|
+
}
|
|
908
|
+
}
|
|
909
|
+
|
|
884
910
|
// Exchange code for tokens
|
|
885
911
|
const spinner = ora({ text: 'EXCHANGING CODE FOR TOKENS...', color: 'cyan' }).start();
|
|
886
912
|
|
|
887
913
|
let result;
|
|
888
914
|
if (provider.id === 'anthropic') {
|
|
889
|
-
result = await config.oauthModule.exchange(code
|
|
915
|
+
result = await config.oauthModule.exchange(code, verifier);
|
|
890
916
|
} else if (provider.id === 'gemini') {
|
|
891
|
-
result = await config.oauthModule.exchange(code
|
|
917
|
+
result = await config.oauthModule.exchange(code);
|
|
892
918
|
} else if (provider.id === 'iflow') {
|
|
893
|
-
result = await config.oauthModule.exchange(code
|
|
919
|
+
result = await config.oauthModule.exchange(code, redirectUri);
|
|
894
920
|
} else {
|
|
895
|
-
result = await config.oauthModule.exchange(code
|
|
921
|
+
result = await config.oauthModule.exchange(code, verifier);
|
|
896
922
|
}
|
|
897
923
|
|
|
898
924
|
if (result.type === 'failed') {
|
|
@@ -901,7 +927,7 @@ const setupBrowserOAuth = async (provider, config) => {
|
|
|
901
927
|
return await selectProviderOption(provider);
|
|
902
928
|
}
|
|
903
929
|
|
|
904
|
-
spinner.
|
|
930
|
+
spinner.text = 'FETCHING AVAILABLE MODELS...';
|
|
905
931
|
|
|
906
932
|
// Store OAuth credentials
|
|
907
933
|
const credentials = {
|
|
@@ -919,15 +945,35 @@ const setupBrowserOAuth = async (provider, config) => {
|
|
|
919
945
|
credentials.apiKey = result.apiKey;
|
|
920
946
|
}
|
|
921
947
|
|
|
922
|
-
//
|
|
948
|
+
// Fetch available models for the provider
|
|
949
|
+
let models = [];
|
|
950
|
+
try {
|
|
951
|
+
const { fetchModelsWithOAuth } = require('../services/ai/client');
|
|
952
|
+
models = await fetchModelsWithOAuth(provider.id, result.access);
|
|
953
|
+
} catch (e) {
|
|
954
|
+
// Fallback to default models if fetch fails
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
// Fallback default models if API doesn't return list
|
|
923
958
|
const defaultModels = {
|
|
924
|
-
anthropic: 'claude-sonnet-4-20250514',
|
|
925
|
-
openai: 'gpt-4o',
|
|
926
|
-
gemini: 'gemini-2.5-pro',
|
|
927
|
-
iflow: 'deepseek-v3'
|
|
959
|
+
anthropic: ['claude-sonnet-4-20250514', 'claude-opus-4-20250514', 'claude-3-5-sonnet-20241022', 'claude-3-5-haiku-20241022'],
|
|
960
|
+
openai: ['gpt-4o', 'gpt-4o-mini', 'gpt-4-turbo', 'o1', 'o1-mini', 'o3-mini'],
|
|
961
|
+
gemini: ['gemini-2.5-pro', 'gemini-2.5-flash', 'gemini-2.0-flash', 'gemini-1.5-pro'],
|
|
962
|
+
iflow: ['deepseek-v3', 'deepseek-chat', 'kimi', 'glm-4']
|
|
928
963
|
};
|
|
929
964
|
|
|
930
|
-
|
|
965
|
+
if (!models || models.length === 0) {
|
|
966
|
+
models = defaultModels[provider.id] || ['default'];
|
|
967
|
+
spinner.warn('USING DEFAULT MODEL LIST');
|
|
968
|
+
} else {
|
|
969
|
+
spinner.succeed(`FOUND ${models.length} MODELS`);
|
|
970
|
+
}
|
|
971
|
+
|
|
972
|
+
// Let user select model
|
|
973
|
+
const selectedModel = await selectModelFromList(models, config.name);
|
|
974
|
+
if (!selectedModel) {
|
|
975
|
+
return await selectProviderOption(provider);
|
|
976
|
+
}
|
|
931
977
|
|
|
932
978
|
// Add agent with OAuth credentials
|
|
933
979
|
try {
|
|
@@ -1040,7 +1086,7 @@ const setupDeviceFlowOAuth = async (provider, config) => {
|
|
|
1040
1086
|
return await selectProviderOption(provider);
|
|
1041
1087
|
}
|
|
1042
1088
|
|
|
1043
|
-
pollSpinner.
|
|
1089
|
+
pollSpinner.text = 'FETCHING AVAILABLE MODELS...';
|
|
1044
1090
|
|
|
1045
1091
|
// Store OAuth credentials
|
|
1046
1092
|
const credentials = {
|
|
@@ -1052,7 +1098,16 @@ const setupDeviceFlowOAuth = async (provider, config) => {
|
|
|
1052
1098
|
}
|
|
1053
1099
|
};
|
|
1054
1100
|
|
|
1055
|
-
|
|
1101
|
+
// Default models for Qwen
|
|
1102
|
+
const defaultModels = ['qwen3-coder-plus', 'qwen3-235b', 'qwen-max', 'qwen-plus', 'qwen-turbo'];
|
|
1103
|
+
|
|
1104
|
+
pollSpinner.succeed('AUTHENTICATION SUCCESSFUL');
|
|
1105
|
+
|
|
1106
|
+
// Let user select model
|
|
1107
|
+
const selectedModel = await selectModelFromList(defaultModels, config.name);
|
|
1108
|
+
if (!selectedModel) {
|
|
1109
|
+
return await selectProviderOption(provider);
|
|
1110
|
+
}
|
|
1056
1111
|
|
|
1057
1112
|
// Add agent with OAuth credentials
|
|
1058
1113
|
try {
|
|
@@ -565,6 +565,47 @@ const fetchOpenAIModels = async (endpoint, apiKey) => {
|
|
|
565
565
|
}
|
|
566
566
|
};
|
|
567
567
|
|
|
568
|
+
/**
|
|
569
|
+
* Fetch available models for OAuth-authenticated providers
|
|
570
|
+
* @param {string} providerId - Provider ID (anthropic, openai, gemini, etc.)
|
|
571
|
+
* @param {string} accessToken - OAuth access token
|
|
572
|
+
* @returns {Promise<Array|null>} Array of model IDs or null on error
|
|
573
|
+
*/
|
|
574
|
+
const fetchModelsWithOAuth = async (providerId, accessToken) => {
|
|
575
|
+
if (!accessToken) return null;
|
|
576
|
+
|
|
577
|
+
try {
|
|
578
|
+
switch (providerId) {
|
|
579
|
+
case 'anthropic':
|
|
580
|
+
return await fetchAnthropicModelsOAuth(accessToken);
|
|
581
|
+
|
|
582
|
+
case 'openai':
|
|
583
|
+
// OpenAI OAuth uses the same endpoint as API key
|
|
584
|
+
return await fetchOpenAIModels('https://api.openai.com/v1', accessToken);
|
|
585
|
+
|
|
586
|
+
case 'gemini':
|
|
587
|
+
// Gemini OAuth - try to fetch from API
|
|
588
|
+
const geminiUrl = 'https://generativelanguage.googleapis.com/v1/models';
|
|
589
|
+
const geminiHeaders = {
|
|
590
|
+
'Authorization': `Bearer ${accessToken}`
|
|
591
|
+
};
|
|
592
|
+
const geminiResponse = await makeRequest(geminiUrl, { method: 'GET', headers: geminiHeaders, timeout: 10000 });
|
|
593
|
+
if (geminiResponse.models && Array.isArray(geminiResponse.models)) {
|
|
594
|
+
return geminiResponse.models
|
|
595
|
+
.filter(m => m.supportedGenerationMethods?.includes('generateContent'))
|
|
596
|
+
.map(m => m.name.replace('models/', ''))
|
|
597
|
+
.filter(Boolean);
|
|
598
|
+
}
|
|
599
|
+
return null;
|
|
600
|
+
|
|
601
|
+
default:
|
|
602
|
+
return null;
|
|
603
|
+
}
|
|
604
|
+
} catch (error) {
|
|
605
|
+
return null;
|
|
606
|
+
}
|
|
607
|
+
};
|
|
608
|
+
|
|
568
609
|
module.exports = {
|
|
569
610
|
callAI,
|
|
570
611
|
analyzeTrading,
|
|
@@ -577,5 +618,6 @@ module.exports = {
|
|
|
577
618
|
fetchAnthropicModelsOAuth,
|
|
578
619
|
fetchGeminiModels,
|
|
579
620
|
fetchOpenAIModels,
|
|
621
|
+
fetchModelsWithOAuth,
|
|
580
622
|
getValidOAuthToken
|
|
581
623
|
};
|