@exreve/exk 1.0.65 → 1.0.67

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.
@@ -60,6 +60,8 @@ const DEFAULT_AI_MODEL = 'glm-5.1';
60
60
  /** TTL cache for ai-config.json reads to avoid hitting disk on every call */
61
61
  let _aiConfigCache = null;
62
62
  const AI_CONFIG_TTL_MS = 5_000;
63
+ // Provider registry — built dynamically from server-provided model list.
64
+ // Falls back to a minimal default set if config not yet fetched.
63
65
  const PROVIDERS = {
64
66
  zai: {
65
67
  apiKey: process.env.ZHIPU_API_KEY || '',
@@ -67,21 +69,52 @@ const PROVIDERS = {
67
69
  models: ['glm-5.1', 'glm-4.7', 'glm-4.5-air'],
68
70
  },
69
71
  minimax: {
70
- apiKey: '', // Populated from ai-config.json (served by backend)
72
+ apiKey: '',
71
73
  baseUrl: 'https://api.minimax.io/anthropic',
72
74
  models: ['MiniMax-M2.7', 'MiniMax-M2.7-highspeed'],
73
75
  },
74
76
  openrouter: {
75
- apiKey: '', // Populated from ai-config.json openrouterApiKey (served by backend)
77
+ apiKey: '',
76
78
  baseUrl: 'https://openrouter.ai/api',
77
79
  models: ['gpt-oss-120b:cerebras'],
78
80
  },
79
81
  cerebras: {
80
- apiKey: '', // Populated from ai-config.json cerebrasApiKey (served by backend)
81
- baseUrl: '', // Set dynamically when proxy starts
82
+ apiKey: '',
83
+ baseUrl: '',
82
84
  models: ['zai-glm-4.7'],
83
85
  },
86
+ kimi: {
87
+ apiKey: '',
88
+ baseUrl: 'https://api.kimi.com/coding',
89
+ models: ['kimi-k2.6'],
90
+ },
84
91
  };
92
+ /** Rebuild PROVIDERS from the models array saved in ai-config.json */
93
+ function rebuildProvidersFromConfig(models) {
94
+ if (!models || models.length === 0)
95
+ return;
96
+ // Group models by provider
97
+ const providerModels = {};
98
+ const providerUrls = {};
99
+ for (const m of models) {
100
+ if (!providerModels[m.provider])
101
+ providerModels[m.provider] = [];
102
+ if (!providerModels[m.provider].includes(m.id))
103
+ providerModels[m.provider].push(m.id);
104
+ if (m.providerBaseUrl)
105
+ providerUrls[m.provider] = m.providerBaseUrl;
106
+ }
107
+ // Update existing providers and add new ones
108
+ for (const [providerId, modelIds] of Object.entries(providerModels)) {
109
+ if (!PROVIDERS[providerId]) {
110
+ PROVIDERS[providerId] = { apiKey: '', baseUrl: providerUrls[providerId] || '', models: [] };
111
+ }
112
+ PROVIDERS[providerId].models = modelIds;
113
+ if (providerUrls[providerId] && providerId !== 'cerebras') {
114
+ PROVIDERS[providerId].baseUrl = providerUrls[providerId];
115
+ }
116
+ }
117
+ }
85
118
  /** Resolve which provider to use based on model name or explicit provider ID.
86
119
  * 1. Populate provider API keys from ai-config.json (served by backend).
87
120
  * 2. If explicit providerId is given and has an API key configured, use that provider.
@@ -93,6 +126,7 @@ function resolveProvider(model, providerId) {
93
126
  PROVIDERS.minimax.apiKey = aiConfig.minimaxApiKey || process.env.MINIMAX_API_KEY || '';
94
127
  PROVIDERS.openrouter.apiKey = aiConfig.openrouterApiKey || process.env.OPENROUTER_API_KEY || '';
95
128
  PROVIDERS.cerebras.apiKey = aiConfig.cerebrasApiKey || process.env.CEREBRAS_API_KEY || '';
129
+ PROVIDERS.kimi.apiKey = aiConfig.kimiApiKey || process.env.KIMI_API_KEY || '';
96
130
  if (!PROVIDERS.zai.apiKey)
97
131
  PROVIDERS.zai.apiKey = aiConfig.apiKey || '';
98
132
  // 1. Explicit provider selection
@@ -129,12 +163,18 @@ function loadAiConfig() {
129
163
  const minimaxApiKey = typeof config.minimaxApiKey === 'string' ? config.minimaxApiKey.trim() : '';
130
164
  const openrouterApiKey = typeof config.openrouterApiKey === 'string' ? config.openrouterApiKey.trim() : '';
131
165
  const cerebrasApiKey = typeof config.cerebrasApiKey === 'string' ? config.cerebrasApiKey.trim() : '';
132
- const result = { apiKey, baseUrl, model, proxy, minimaxApiKey, openrouterApiKey, cerebrasApiKey };
166
+ const kimiApiKey = typeof config.kimiApiKey === 'string' ? config.kimiApiKey.trim() : '';
167
+ const models = config.models;
168
+ // Rebuild provider registry from server-provided model list
169
+ if (models && models.length > 0) {
170
+ rebuildProvidersFromConfig(models);
171
+ }
172
+ const result = { apiKey, baseUrl, model, proxy, minimaxApiKey, openrouterApiKey, cerebrasApiKey, kimiApiKey, models };
133
173
  _aiConfigCache = { data: result, ts: now };
134
174
  return result;
135
175
  }
136
176
  catch {
137
- const fallback = { apiKey: '', baseUrl: '', model: DEFAULT_AI_MODEL, proxy: '', minimaxApiKey: '', openrouterApiKey: '', cerebrasApiKey: '' };
177
+ const fallback = { apiKey: '', baseUrl: '', model: DEFAULT_AI_MODEL, proxy: '', minimaxApiKey: '', openrouterApiKey: '', cerebrasApiKey: '', kimiApiKey: '', models: [] };
138
178
  _aiConfigCache = { data: fallback, ts: now };
139
179
  return fallback;
140
180
  }
@@ -217,6 +257,14 @@ function envForClaudeCodeChild(_localModel, resolvedProvider) {
217
257
  env.ANTHROPIC_DEFAULT_HAIKU_MODEL = resolvedProvider.model;
218
258
  env.CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC = '1';
219
259
  }
260
+ // For Kimi specifically: override ALL model aliases
261
+ if (resolvedProvider?.provider === 'kimi') {
262
+ env.ANTHROPIC_MODEL = resolvedProvider.model;
263
+ env.ANTHROPIC_DEFAULT_SONNET_MODEL = resolvedProvider.model;
264
+ env.ANTHROPIC_DEFAULT_OPUS_MODEL = resolvedProvider.model;
265
+ env.ANTHROPIC_DEFAULT_HAIKU_MODEL = resolvedProvider.model;
266
+ env.CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC = '1';
267
+ }
220
268
  // Apply proxy if enabled
221
269
  const proxyToggle = readProxyToggle();
222
270
  if (proxyToggle.enabled && proxy) {
@@ -634,6 +682,14 @@ export class AgentSessionManager {
634
682
  settingsEnv.ANTHROPIC_DEFAULT_HAIKU_MODEL = resolved.model;
635
683
  settingsEnv.CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC = '1';
636
684
  }
685
+ // For Kimi: also override all model aliases in settings
686
+ if (resolved.provider === 'kimi') {
687
+ settingsEnv.ANTHROPIC_MODEL = resolved.model;
688
+ settingsEnv.ANTHROPIC_DEFAULT_SONNET_MODEL = resolved.model;
689
+ settingsEnv.ANTHROPIC_DEFAULT_OPUS_MODEL = resolved.model;
690
+ settingsEnv.ANTHROPIC_DEFAULT_HAIKU_MODEL = resolved.model;
691
+ settingsEnv.CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC = '1';
692
+ }
637
693
  // For Cerebras: start anthropic-proxy-rs and route through it
638
694
  if (resolved.provider === 'cerebras') {
639
695
  const proxyUrl = await ensureProxy({
@@ -84,7 +84,9 @@ async function fetchAiConfig(authToken) {
84
84
  console.log('[fetchAiConfig] No AI config available for this user');
85
85
  return false;
86
86
  }
87
- await fs.writeFile(AI_CONFIG_FILE, JSON.stringify(data.aiConfig, null, 2));
87
+ // Save aiConfig + models together so agentSession can build provider registry dynamically
88
+ const configPayload = { ...data.aiConfig, models: data.models || [] };
89
+ await fs.writeFile(AI_CONFIG_FILE, JSON.stringify(configPayload, null, 2));
88
90
  console.log('[fetchAiConfig] AI config saved successfully');
89
91
  return true;
90
92
  }
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@exreve/exk",
3
- "version": "1.0.65",
3
+ "version": "1.0.67",
4
4
  "description": "exk - Control Claude CLI with voice and programmable interfaces",
5
5
  "type": "module",
6
6
  "bin": {