@darksol/terminal 0.9.0 → 0.9.2

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/src/cli.js CHANGED
@@ -29,8 +29,10 @@ import { listSkills, installSkill, skillInfo, uninstallSkill } from './services/
29
29
  import { runSetupWizard } from './setup/wizard.js';
30
30
  import { displaySoul, hasSoul, resetSoul, runSoulSetup } from './soul/index.js';
31
31
  import { clearMemories, exportMemories, getRecentMemories, searchMemories } from './memory/index.js';
32
+ import { getAgentStatus, planAgentGoal, runAgentTask } from './agent/index.js';
32
33
  import { createRequire } from 'module';
33
34
  import { resolve } from 'path';
35
+ import { getConfiguredModel, getProviderDefaultModel } from './llm/models.js';
34
36
  const require = createRequire(import.meta.url);
35
37
  const { version: PKG_VERSION } = require('../package.json');
36
38
 
@@ -764,7 +766,7 @@ export function cli(argv) {
764
766
  ai
765
767
  .command('chat')
766
768
  .description('Start interactive AI trading chat')
767
- .option('-p, --provider <name>', 'LLM provider (openai, anthropic, openrouter, ollama)')
769
+ .option('-p, --provider <name>', 'LLM provider (openai, anthropic, openrouter, minimax, ollama)')
768
770
  .option('-m, --model <model>', 'Model name')
769
771
  .action((opts) => startChat(opts));
770
772
 
@@ -883,6 +885,93 @@ export function cli(argv) {
883
885
  .command('agent')
884
886
  .description('Secure agent signer — PK-isolated wallet for AI agents');
885
887
 
888
+ agent
889
+ .command('task <goal...>')
890
+ .description('Run the agent loop against a goal')
891
+ .option('--max-steps <n>', 'Maximum loop steps', '10')
892
+ .option('--allow-actions', 'Allow mutating tools such as swap/send/script-run')
893
+ .action(async (goalParts, opts) => {
894
+ showMiniBanner();
895
+ showSection('AGENT TASK');
896
+ const goal = goalParts.join(' ').trim();
897
+ info(`Goal: ${goal}`);
898
+ info(`Mode: ${opts.allowActions ? 'actions enabled' : 'safe mode'}`);
899
+ console.log('');
900
+
901
+ const result = await runAgentTask(goal, {
902
+ maxSteps: parseInt(opts.maxSteps, 10),
903
+ allowActions: opts.allowActions,
904
+ onProgress: (event) => {
905
+ if (event.type === 'thought') {
906
+ info(`Step ${event.step}: ${event.action}`);
907
+ if (event.thought) console.log(` ${theme.dim(event.thought)}`);
908
+ }
909
+ if (event.type === 'observation') {
910
+ const summary = event.observation?.summary || event.observation?.error || '';
911
+ if (summary) console.log(` ${theme.dim(summary)}`);
912
+ console.log('');
913
+ }
914
+ },
915
+ });
916
+
917
+ showSection('AGENT RESULT');
918
+ kvDisplay([
919
+ ['Status', result.status],
920
+ ['Steps', `${result.stepsTaken}/${result.maxSteps}`],
921
+ ['Stop Reason', result.stopReason],
922
+ ]);
923
+ console.log('');
924
+ if (result.final) {
925
+ success(result.final);
926
+ console.log('');
927
+ }
928
+ });
929
+
930
+ agent
931
+ .command('plan <goal...>')
932
+ .description('Generate a concise agent plan for a goal')
933
+ .action(async (goalParts) => {
934
+ showMiniBanner();
935
+ showSection('AGENT PLAN');
936
+ const goal = goalParts.join(' ').trim();
937
+ const plan = await planAgentGoal(goal);
938
+ info(plan.summary);
939
+ console.log('');
940
+ plan.steps.forEach((step, index) => console.log(` ${theme.gold(String(index + 1).padStart(2, ' '))}. ${step}`));
941
+ console.log('');
942
+ });
943
+
944
+ agent
945
+ .command('status')
946
+ .description('Show the latest agent task or plan status')
947
+ .action(() => {
948
+ showMiniBanner();
949
+ showSection('AGENT STATUS');
950
+ const status = getAgentStatus();
951
+ if (!status || !status.status) {
952
+ warn('No agent runs recorded yet.');
953
+ console.log('');
954
+ return;
955
+ }
956
+
957
+ kvDisplay([
958
+ ['Status', status.status || '-'],
959
+ ['Goal', status.goal || '-'],
960
+ ['Summary', status.summary || '-'],
961
+ ['Steps', status.maxSteps ? `${status.stepsTaken || 0}/${status.maxSteps}` : String(status.stepsTaken || 0)],
962
+ ['Actions', status.allowActions ? 'enabled' : 'safe mode'],
963
+ ['Started', status.startedAt || '-'],
964
+ ['Completed', status.completedAt || '-'],
965
+ ['Updated', status.updatedAt || '-'],
966
+ ]);
967
+ if (Array.isArray(status.plan) && status.plan.length > 0) {
968
+ console.log('');
969
+ showSection('LAST PLAN');
970
+ status.plan.forEach((step) => console.log(` ${theme.dim(step)}`));
971
+ }
972
+ console.log('');
973
+ });
974
+
886
975
  agent
887
976
  .command('start [wallet]')
888
977
  .description('Start the agent signing proxy')
@@ -1049,6 +1138,8 @@ export function cli(argv) {
1049
1138
  ['Output', cfg.output],
1050
1139
  ['Slippage', `${cfg.slippage}%`],
1051
1140
  ['Gas Multiplier', `${cfg.gasMultiplier}x`],
1141
+ ['LLM Provider', cfg.llm?.provider || theme.dim('(not set)')],
1142
+ ['LLM Model', getConfiguredModel(cfg.llm?.provider || 'openai') || theme.dim('(default)')],
1052
1143
  ['Soul User', cfg.soul?.userName || theme.dim('(not set)')],
1053
1144
  ['Agent Name', cfg.soul?.agentName || 'Darksol'],
1054
1145
  ['Tone', cfg.soul?.tone || theme.dim('(not set)')],
@@ -1065,6 +1156,33 @@ export function cli(argv) {
1065
1156
  console.log('');
1066
1157
  });
1067
1158
 
1159
+ config
1160
+ .command('model [model]')
1161
+ .description('Set the LLM model')
1162
+ .option('-p, --provider <provider>', 'LLM provider (defaults to current provider)')
1163
+ .action((model, opts) => {
1164
+ const provider = opts.provider || getConfig('llm.provider') || 'openai';
1165
+ if (!model) {
1166
+ const current = getConfiguredModel(provider);
1167
+ const fallback = getProviderDefaultModel(provider);
1168
+ info(`Current model for ${provider}: ${current || '(not set)'}`);
1169
+ if (fallback) {
1170
+ info(`Provider default: ${fallback}`);
1171
+ }
1172
+ return;
1173
+ }
1174
+
1175
+ if (opts.provider) {
1176
+ setConfig('llm.provider', provider);
1177
+ setConfig('llmProvider', provider);
1178
+ }
1179
+ setConfig('llm.model', model);
1180
+ if (provider === 'ollama') {
1181
+ setConfig('ollamaModel', model);
1182
+ }
1183
+ success(`LLM model for ${provider}: ${model}`);
1184
+ });
1185
+
1068
1186
  config
1069
1187
  .command('set <key> <value>')
1070
1188
  .description('Set config value')
@@ -1304,7 +1422,7 @@ function showCommandList() {
1304
1422
  ['dca', 'Dollar-cost averaging orders'],
1305
1423
  ['ai chat', 'Standalone AI chat session'],
1306
1424
  ['ai execute', 'Parse + execute a trade via AI'],
1307
- ['agent start', 'Start secure agent signer'],
1425
+ ['agent task', 'Run bounded agent loop for a goal'],
1308
1426
  ['keys', 'API key vault'],
1309
1427
  ['soul', 'Identity and agent personality'],
1310
1428
  ['memory', 'Persistent cross-session memory'],
@@ -84,6 +84,14 @@ export const SERVICES = {
84
84
  docsUrl: 'https://openrouter.ai/keys',
85
85
  validate: (key) => key.startsWith('sk-or-'),
86
86
  },
87
+ minimax: {
88
+ name: 'MiniMax',
89
+ category: 'llm',
90
+ description: 'MiniMax-M2.5 via OpenAI-compatible chat completions',
91
+ envVar: 'MINIMAX_API_KEY',
92
+ docsUrl: 'https://platform.minimax.io/docs/guides/models-intro',
93
+ validate: (key) => key.length > 10,
94
+ },
87
95
  ollama: {
88
96
  name: 'Ollama (Local)',
89
97
  category: 'llm',
@@ -420,7 +428,7 @@ export function hasKey(service) {
420
428
  */
421
429
  export function hasAnyLLM() {
422
430
  // Cloud providers — need real validated API keys
423
- if (['openai', 'anthropic', 'openrouter', 'bankr'].some(s => hasKey(s))) return true;
431
+ if (['openai', 'anthropic', 'openrouter', 'minimax', 'bankr'].some(s => hasKey(s))) return true;
424
432
  // Ollama — check if explicitly configured via hasKey (validates URL format)
425
433
  if (hasKey('ollama')) return true;
426
434
  return false;
@@ -28,6 +28,22 @@ const config = new Conf({
28
28
  createdAt: '',
29
29
  },
30
30
  },
31
+ agentState: {
32
+ type: 'object',
33
+ default: {
34
+ status: '',
35
+ goal: '',
36
+ summary: '',
37
+ plan: [],
38
+ stepsTaken: 0,
39
+ maxSteps: 0,
40
+ allowActions: false,
41
+ startedAt: null,
42
+ completedAt: null,
43
+ stopReason: '',
44
+ updatedAt: null,
45
+ },
46
+ },
31
47
  dca: {
32
48
  type: 'object',
33
49
  default: {
package/src/llm/engine.js CHANGED
@@ -3,18 +3,19 @@ import { getKeyFromEnv, getKey } from '../config/keys.js';
3
3
  import { getConfig } from '../config/store.js';
4
4
  import { SessionMemory, extractMemories, searchMemories } from '../memory/index.js';
5
5
  import { formatSystemPrompt as formatSoulSystemPrompt } from '../soul/index.js';
6
+ import { getProviderDefaultModel } from './models.js';
6
7
 
7
8
  const PROVIDERS = {
8
9
  openai: {
9
10
  url: 'https://api.openai.com/v1/chat/completions',
10
- defaultModel: 'gpt-4o',
11
+ defaultModel: getProviderDefaultModel('openai'),
11
12
  authHeader: (key) => ({ Authorization: `Bearer ${key}` }),
12
13
  parseResponse: (data) => data.choices?.[0]?.message?.content,
13
14
  parseUsage: (data) => data.usage,
14
15
  },
15
16
  anthropic: {
16
17
  url: 'https://api.anthropic.com/v1/messages',
17
- defaultModel: 'claude-sonnet-4-20250514',
18
+ defaultModel: getProviderDefaultModel('anthropic'),
18
19
  authHeader: (key) => ({ 'x-api-key': key, 'anthropic-version': '2023-06-01' }),
19
20
  buildBody: (model, messages, systemPrompt) => ({
20
21
  model,
@@ -30,7 +31,7 @@ const PROVIDERS = {
30
31
  },
31
32
  openrouter: {
32
33
  url: 'https://openrouter.ai/api/v1/chat/completions',
33
- defaultModel: 'anthropic/claude-sonnet-4-20250514',
34
+ defaultModel: getProviderDefaultModel('openrouter'),
34
35
  authHeader: (key) => ({
35
36
  Authorization: `Bearer ${key}`,
36
37
  'HTTP-Referer': 'https://darksol.net',
@@ -39,16 +40,23 @@ const PROVIDERS = {
39
40
  parseResponse: (data) => data.choices?.[0]?.message?.content,
40
41
  parseUsage: (data) => data.usage,
41
42
  },
43
+ minimax: {
44
+ url: 'https://api.minimax.io/v1/chat/completions',
45
+ defaultModel: getProviderDefaultModel('minimax'),
46
+ authHeader: (key) => ({ Authorization: `Bearer ${key}` }),
47
+ parseResponse: (data) => data.choices?.[0]?.message?.content,
48
+ parseUsage: (data) => data.usage,
49
+ },
42
50
  ollama: {
43
51
  url: null,
44
- defaultModel: 'llama3.1',
52
+ defaultModel: getProviderDefaultModel('ollama'),
45
53
  authHeader: () => ({}),
46
54
  parseResponse: (data) => data.choices?.[0]?.message?.content || data.message?.content,
47
55
  parseUsage: () => ({ input: 0, output: 0 }),
48
56
  },
49
57
  bankr: {
50
58
  url: 'https://llm.bankr.bot/v1/chat/completions',
51
- defaultModel: 'claude-sonnet-4.6',
59
+ defaultModel: getProviderDefaultModel('bankr'),
52
60
  authHeader: (key) => ({ 'X-API-Key': key }),
53
61
  parseResponse: (data) => data.choices?.[0]?.message?.content,
54
62
  parseUsage: (data) => data.usage,
@@ -92,9 +100,7 @@ export class LLMEngine {
92
100
  throw new Error(`Unknown LLM provider: ${this.provider}. Supported: ${Object.keys(PROVIDERS).join(', ')}`);
93
101
  }
94
102
 
95
- if (!this.model) {
96
- this.model = providerConfig.defaultModel;
97
- }
103
+ this.model = this.model || providerConfig.defaultModel || getProviderDefaultModel(this.provider);
98
104
 
99
105
  if (this.provider === 'ollama') {
100
106
  const host = this.apiKey || getConfig('llm.ollamaHost') || 'http://localhost:11434';
@@ -0,0 +1,67 @@
1
+ import { getConfig } from '../config/store.js';
2
+
3
+ export const MODEL_CATALOG = {
4
+ openai: {
5
+ defaultModel: 'gpt-5.4',
6
+ choices: [
7
+ { value: 'gpt-5.4', label: 'gpt-5.4', desc: 'flagship, complex reasoning' },
8
+ { value: 'gpt-5-mini', label: 'gpt-5-mini', desc: 'fast, lower cost' },
9
+ { value: 'gpt-4o', label: 'gpt-4o', desc: 'previous gen, still good' },
10
+ { value: 'o3', label: 'o3', desc: 'reasoning model' },
11
+ ],
12
+ },
13
+ anthropic: {
14
+ defaultModel: 'claude-sonnet-4-6',
15
+ choices: [
16
+ { value: 'claude-opus-4-6', label: 'claude-opus-4-6', desc: 'most intelligent, agents+coding' },
17
+ { value: 'claude-sonnet-4-6', label: 'claude-sonnet-4-6', desc: 'best speed/intelligence balance' },
18
+ { value: 'claude-haiku-4-5', label: 'claude-haiku-4-5', desc: 'fastest, near-frontier' },
19
+ ],
20
+ },
21
+ openrouter: {
22
+ defaultModel: 'anthropic/claude-sonnet-4-6',
23
+ choices: [
24
+ { value: 'anthropic/claude-sonnet-4-6', label: 'anthropic/claude-sonnet-4-6', desc: 'popular pick' },
25
+ { value: 'openai/gpt-5.4', label: 'openai/gpt-5.4', desc: 'popular pick' },
26
+ { value: 'google/gemini-2.5-pro', label: 'google/gemini-2.5-pro', desc: 'popular pick' },
27
+ { value: 'meta-llama/llama-4-maverick', label: 'meta-llama/llama-4-maverick', desc: 'popular pick' },
28
+ { value: 'deepseek/deepseek-r1', label: 'deepseek/deepseek-r1', desc: 'popular pick' },
29
+ ],
30
+ allowCustom: true,
31
+ },
32
+ minimax: {
33
+ defaultModel: 'MiniMax-M2.5',
34
+ choices: [
35
+ { value: 'MiniMax-M2.5', label: 'MiniMax-M2.5', desc: 'flagship, 204K context, ~60 tps' },
36
+ { value: 'MiniMax-M2.5-highspeed', label: 'MiniMax-M2.5-highspeed', desc: 'same perf, ~100 tps' },
37
+ { value: 'MiniMax-M2.1', label: 'MiniMax-M2.1', desc: 'code-focused' },
38
+ { value: 'MiniMax-M2.1-highspeed', label: 'MiniMax-M2.1-highspeed', desc: 'code-focused, faster' },
39
+ { value: 'MiniMax-M2', label: 'MiniMax-M2', desc: 'agentic, advanced reasoning' },
40
+ ],
41
+ },
42
+ ollama: {
43
+ defaultModel: 'llama3.1',
44
+ textInput: true,
45
+ },
46
+ bankr: {
47
+ defaultModel: 'claude-sonnet-4.6',
48
+ managed: true,
49
+ },
50
+ };
51
+
52
+ export function getProviderDefaultModel(provider) {
53
+ return MODEL_CATALOG[provider]?.defaultModel || null;
54
+ }
55
+
56
+ export function getConfiguredProvider(fallback = 'openai') {
57
+ return getConfig('llm.provider') || fallback;
58
+ }
59
+
60
+ export function getConfiguredModel(provider = getConfiguredProvider()) {
61
+ const configured = getConfig('llm.model');
62
+ return configured || getProviderDefaultModel(provider);
63
+ }
64
+
65
+ export function getModelSelectionMeta(provider = getConfiguredProvider()) {
66
+ return MODEL_CATALOG[provider] || { defaultModel: null };
67
+ }
@@ -8,6 +8,7 @@ import { hasSoul, runSoulSetup } from '../soul/index.js';
8
8
  import { createServer } from 'http';
9
9
  import open from 'open';
10
10
  import crypto from 'crypto';
11
+ import { getModelSelectionMeta } from '../llm/models.js';
11
12
 
12
13
  // ══════════════════════════════════════════════════
13
14
  // FIRST-RUN SETUP WIZARD
@@ -52,11 +53,12 @@ export async function runSetupWizard(opts = {}) {
52
53
  name: 'provider',
53
54
  message: theme.gold('Choose your AI provider:'),
54
55
  choices: [
55
- { name: '🤖 OpenAI (GPT-4o, GPT-5) API key or OAuth', value: 'openai' },
56
- { name: '🧠 Anthropic (Claude Opus, Sonnet) API key or OAuth', value: 'anthropic' },
57
- { name: '🔀 OpenRouter (any model, one key) API key', value: 'openrouter' },
58
- { name: '🏠 Ollama (local models, free, private) no key needed', value: 'ollama' },
59
- { name: '⏭️ Skip for now', value: 'skip' },
56
+ { name: 'OpenAI (GPT-4o, GPT-5) - API key or OAuth', value: 'openai' },
57
+ { name: 'Anthropic (Claude Opus, Sonnet) - API key or OAuth', value: 'anthropic' },
58
+ { name: 'OpenRouter (any model, one key) - API key', value: 'openrouter' },
59
+ { name: 'MiniMax (MiniMax-M2.5) - API key', value: 'minimax' },
60
+ { name: 'Ollama (local models, free, private) - no key needed', value: 'ollama' },
61
+ { name: 'Skip for now', value: 'skip' },
60
62
  ],
61
63
  }]);
62
64
 
@@ -112,14 +114,17 @@ export async function runSetupWizard(opts = {}) {
112
114
  }
113
115
 
114
116
  /**
115
- * Setup a cloud provider (OpenAI, Anthropic, OpenRouter)
117
+ * Setup a cloud provider (OpenAI, Anthropic, OpenRouter, MiniMax)
116
118
  */
117
119
  async function setupCloudProvider(provider) {
120
+ await selectAndSaveModel(provider);
121
+
118
122
  const supportsOAuth = ['openai', 'anthropic'].includes(provider);
119
123
  const providerName = {
120
124
  openai: 'OpenAI',
121
125
  anthropic: 'Anthropic',
122
126
  openrouter: 'OpenRouter',
127
+ minimax: 'MiniMax',
123
128
  }[provider];
124
129
 
125
130
  if (supportsOAuth) {
@@ -156,6 +161,7 @@ async function setupAPIKey(provider) {
156
161
  openai: 'OpenAI',
157
162
  anthropic: 'Anthropic',
158
163
  openrouter: 'OpenRouter',
164
+ minimax: 'MiniMax',
159
165
  }[provider];
160
166
 
161
167
  const { key } = await inquirer.prompt([{
@@ -173,6 +179,7 @@ async function setupAPIKey(provider) {
173
179
  success(`${providerName} key saved (encrypted)`);
174
180
 
175
181
  // Set as default provider
182
+ setConfig('llm.provider', provider);
176
183
  setConfig('llmProvider', provider);
177
184
  info(`Default AI provider set to ${provider}`);
178
185
  }
@@ -193,22 +200,80 @@ async function setupOllama() {
193
200
  default: 'http://localhost:11434',
194
201
  }]);
195
202
 
203
+ setConfig('llm.ollamaHost', host);
196
204
  setConfig('ollamaHost', host);
197
205
 
198
206
  const { model } = await inquirer.prompt([{
199
207
  type: 'input',
200
208
  name: 'model',
201
209
  message: theme.gold('Default model:'),
202
- default: 'llama3',
210
+ default: getModelSelectionMeta('ollama').defaultModel,
211
+ validate: (v) => v.trim().length > 0 || 'Model is required',
203
212
  }]);
204
213
 
205
- setConfig('ollamaModel', model);
214
+ saveModelConfig(model.trim(), 'ollama');
215
+ setConfig('llm.provider', 'ollama');
206
216
  setConfig('llmProvider', 'ollama');
207
217
 
208
218
  success(`Ollama configured: ${host} / ${model}`);
209
219
  info('Make sure Ollama is running: ollama serve');
210
220
  }
211
221
 
222
+ async function selectAndSaveModel(provider) {
223
+ const meta = getModelSelectionMeta(provider);
224
+ if (!meta || meta.managed) return null;
225
+
226
+ if (meta.textInput) {
227
+ const { model } = await inquirer.prompt([{
228
+ type: 'input',
229
+ name: 'model',
230
+ message: theme.gold('Model:'),
231
+ default: meta.defaultModel,
232
+ validate: (v) => v.trim().length > 0 || 'Model is required',
233
+ }]);
234
+ saveModelConfig(model.trim(), provider);
235
+ return model.trim();
236
+ }
237
+
238
+ const choices = (meta.choices || []).map((choice) => ({
239
+ name: `${choice.value} - ${choice.desc}`,
240
+ value: choice.value,
241
+ }));
242
+
243
+ if (meta.allowCustom) {
244
+ choices.push({ name: 'Custom model string', value: '__custom__' });
245
+ }
246
+
247
+ const { selectedModel } = await inquirer.prompt([{
248
+ type: 'list',
249
+ name: 'selectedModel',
250
+ message: theme.gold('Choose model:'),
251
+ choices,
252
+ default: meta.defaultModel,
253
+ }]);
254
+
255
+ if (selectedModel === '__custom__') {
256
+ const { customModel } = await inquirer.prompt([{
257
+ type: 'input',
258
+ name: 'customModel',
259
+ message: theme.gold('Custom model string:'),
260
+ validate: (v) => v.trim().length > 0 || 'Model is required',
261
+ }]);
262
+ saveModelConfig(customModel.trim(), provider);
263
+ return customModel.trim();
264
+ }
265
+
266
+ saveModelConfig(selectedModel, provider);
267
+ return selectedModel;
268
+ }
269
+
270
+ function saveModelConfig(model, provider) {
271
+ setConfig('llm.model', model);
272
+ if (provider === 'ollama') {
273
+ setConfig('ollamaModel', model);
274
+ }
275
+ }
276
+
212
277
  /**
213
278
  * Show instructions for getting API keys
214
279
  */
@@ -231,8 +296,14 @@ function showKeyInstructions(provider) {
231
296
  console.log(theme.dim(' 3. Copy the key (starts with sk-ant-)'));
232
297
  console.log(theme.dim(' 4. Paste it below'));
233
298
  console.log('');
234
- console.log(theme.dim(' 💡 If you have a Claude Pro/Team subscription,'));
299
+ console.log(theme.dim(' If you have a Claude Pro/Team subscription,'));
235
300
  console.log(theme.dim(' you can use OAuth instead.'));
301
+ } else if (provider === 'minimax') {
302
+ showSection('GET A MINIMAX API KEY');
303
+ console.log(theme.dim(' 1. Go to https://platform.minimax.io/docs/guides/models-intro'));
304
+ console.log(theme.dim(' 2. Open your MiniMax developer console / API key page'));
305
+ console.log(theme.dim(' 3. Create or copy an API key'));
306
+ console.log(theme.dim(' 4. Paste it below'));
236
307
  }
237
308
 
238
309
  console.log('');
@@ -432,6 +503,7 @@ async function executeOAuthFlow(provider, clientId, clientSecret) {
432
503
  if (tokenData.refresh_token) {
433
504
  addKeyDirect(`${provider}_refresh`, tokenData.refresh_token);
434
505
  }
506
+ setConfig('llm.provider', provider);
435
507
  setConfig('llmProvider', provider);
436
508
 
437
509
  res.writeHead(200, { 'Content-Type': 'text/html' });