@exreve/exk 1.0.78 → 1.0.80

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.
@@ -56,7 +56,27 @@ const symlinkAsync = promisify(fsSymlink);
56
56
  // AI config - loaded from server after registration, stored in ~/.talk-to-code/ai-config.json
57
57
  // (Do not read ANTHROPIC_* / CLAUDE_MODEL from the host environment — only this file + code default model.)
58
58
  const AI_CONFIG_PATH = path.join(os.homedir(), '.talk-to-code', 'ai-config.json');
59
- const DEFAULT_AI_MODEL = 'glm-5.2';
59
+ const DEFAULT_AI_MODEL = 'GLM-5.2';
60
+ /**
61
+ * Normalize a model ID before sending it to the upstream API.
62
+ *
63
+ * z.ai's API only accepts UPPERCASE model IDs (GLM-5.2, GLM-5.1, etc.). The
64
+ * lowercase form 'glm-5.2' triggers a 529 overloaded_error from z.ai, even
65
+ * though it's a real model on their side. The session schema in MongoDB and
66
+ * existing ai-config.json files may still contain the legacy lowercase form,
67
+ * so we normalize defensively at every read point.
68
+ */
69
+ function normalizeModelId(model) {
70
+ if (!model)
71
+ return DEFAULT_AI_MODEL;
72
+ const m = String(model).trim();
73
+ if (!m)
74
+ return DEFAULT_AI_MODEL;
75
+ // z.ai GLM models must be uppercase
76
+ if (/^glm[-.]/i.test(m))
77
+ return m.toUpperCase();
78
+ return m;
79
+ }
60
80
  /** TTL cache for ai-config.json reads to avoid hitting disk on every call */
61
81
  let _aiConfigCache = null;
62
82
  const AI_CONFIG_TTL_MS = 5_000;
@@ -66,7 +86,7 @@ const PROVIDERS = {
66
86
  zai: {
67
87
  apiKey: process.env.ZHIPU_API_KEY || '',
68
88
  baseUrl: process.env.CLI_AI_BASE_URL || 'https://api.z.ai/api/anthropic',
69
- models: ['glm-5.2'],
89
+ models: ['GLM-5.2'],
70
90
  },
71
91
  minimax: {
72
92
  apiKey: '',
@@ -97,10 +117,11 @@ function rebuildProvidersFromConfig(models) {
97
117
  const providerModels = {};
98
118
  const providerUrls = {};
99
119
  for (const m of models) {
120
+ const id = normalizeModelId(m.id);
100
121
  if (!providerModels[m.provider])
101
122
  providerModels[m.provider] = [];
102
- if (!providerModels[m.provider].includes(m.id))
103
- providerModels[m.provider].push(m.id);
123
+ if (!providerModels[m.provider].includes(id))
124
+ providerModels[m.provider].push(id);
104
125
  if (m.providerBaseUrl)
105
126
  providerUrls[m.provider] = m.providerBaseUrl;
106
127
  }
@@ -129,15 +150,17 @@ function resolveProvider(model, providerId) {
129
150
  PROVIDERS.kimi.apiKey = aiConfig.kimiApiKey || process.env.KIMI_API_KEY || '';
130
151
  if (!PROVIDERS.zai.apiKey)
131
152
  PROVIDERS.zai.apiKey = aiConfig.apiKey || '';
153
+ // Normalize model name for z.ai case-sensitivity
154
+ const normalizedModel = normalizeModelId(model);
132
155
  // 1. Explicit provider selection
133
156
  if (providerId && PROVIDERS[providerId]?.apiKey) {
134
157
  const provider = PROVIDERS[providerId];
135
- return { provider: providerId, apiKey: provider.apiKey, baseUrl: provider.baseUrl, model };
158
+ return { provider: providerId, apiKey: provider.apiKey, baseUrl: provider.baseUrl, model: normalizedModel };
136
159
  }
137
160
  // 2. Match model name to a provider
138
161
  for (const [id, config] of Object.entries(PROVIDERS)) {
139
- if (config.models.includes(model) && config.apiKey) {
140
- return { provider: id, apiKey: config.apiKey, baseUrl: config.baseUrl, model };
162
+ if (config.models.includes(normalizedModel) && config.apiKey) {
163
+ return { provider: id, apiKey: config.apiKey, baseUrl: config.baseUrl, model: normalizedModel };
141
164
  }
142
165
  }
143
166
  // 3. Fallback: use ai-config.json credentials (z.ai default)
@@ -145,7 +168,7 @@ function resolveProvider(model, providerId) {
145
168
  provider: 'zai',
146
169
  apiKey: aiConfig.apiKey,
147
170
  baseUrl: aiConfig.baseUrl || PROVIDERS.zai.baseUrl,
148
- model,
171
+ model: normalizedModel,
149
172
  };
150
173
  }
151
174
  function loadAiConfig() {
@@ -158,7 +181,7 @@ function loadAiConfig() {
158
181
  const config = JSON.parse(data);
159
182
  const apiKey = typeof config.authToken === 'string' ? config.authToken.trim() : '';
160
183
  const baseUrl = typeof config.baseUrl === 'string' ? config.baseUrl.trim() : '';
161
- const model = typeof config.model === 'string' && config.model.trim() ? config.model.trim() : DEFAULT_AI_MODEL;
184
+ const model = normalizeModelId(typeof config.model === 'string' && config.model.trim() ? config.model.trim() : DEFAULT_AI_MODEL);
162
185
  const proxy = typeof config.proxy === 'string' ? config.proxy.trim() : '';
163
186
  const minimaxApiKey = typeof config.minimaxApiKey === 'string' ? config.minimaxApiKey.trim() : '';
164
187
  const openrouterApiKey = typeof config.openrouterApiKey === 'string' ? config.openrouterApiKey.trim() : '';
@@ -239,6 +262,17 @@ function envForClaudeCodeChild(_localModel, resolvedProvider) {
239
262
  env.ANTHROPIC_API_KEY = effectiveApiKey;
240
263
  if (effectiveBaseUrl)
241
264
  env.ANTHROPIC_BASE_URL = effectiveBaseUrl;
265
+ // For z.ai specifically: override ALL model aliases so the SDK
266
+ // sends the correct (UPPERCASE) model ID. z.ai's API is case-sensitive
267
+ // and rejects lowercase 'glm-5.2' with 529 overloaded_error.
268
+ if (resolvedProvider?.provider === 'zai') {
269
+ const m = normalizeModelId(resolvedProvider.model);
270
+ env.ANTHROPIC_MODEL = m;
271
+ env.ANTHROPIC_DEFAULT_SONNET_MODEL = m;
272
+ env.ANTHROPIC_DEFAULT_OPUS_MODEL = m;
273
+ env.ANTHROPIC_DEFAULT_HAIKU_MODEL = m;
274
+ env.CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC = '1';
275
+ }
242
276
  // For MiniMax specifically: override ALL model aliases so the SDK
243
277
  // sends the correct model ID to the Anthropic-compatible endpoint
244
278
  if (resolvedProvider?.provider === 'minimax') {
@@ -401,7 +435,8 @@ export class AgentSessionManager {
401
435
  }
402
436
  async createSession(handler) {
403
437
  const { sessionId, projectPath, model } = handler;
404
- const sessionModel = model || CLAUDE_CONFIG.model;
438
+ // Normalize model name on entry — z.ai rejects lowercase 'glm-5.2' with 529.
439
+ const sessionModel = normalizeModelId(model || CLAUDE_CONFIG.model);
405
440
  // Ensure project directory exists - prevents ENOENT errors when SDK spawns process
406
441
  if (!existsSync(projectPath)) {
407
442
  try {
@@ -678,6 +713,9 @@ export class AgentSessionManager {
678
713
  // Resolve provider for multi-provider switching (Z.ai / MiniMax)
679
714
  const resolved = resolveProvider(sessionModel);
680
715
  console.log(`[agentSession] Resolved provider: ${resolved.provider} for model: ${sessionModel}`);
716
+ // Use the normalized model from resolveProvider so the SDK query() option
717
+ // matches the env vars (otherwise z.ai sees lowercase and returns 529).
718
+ effectiveModel = resolved.model;
681
719
  effectiveApiKey = resolved.apiKey;
682
720
  effectiveEnv = envForClaudeCodeChild(undefined, resolved);
683
721
  effectiveProvider = resolved.provider;
@@ -686,6 +724,15 @@ export class AgentSessionManager {
686
724
  ANTHROPIC_API_KEY: resolved.apiKey,
687
725
  ANTHROPIC_BASE_URL: resolved.baseUrl,
688
726
  };
727
+ // For z.ai: also override all model aliases in settings (case-sensitive)
728
+ if (resolved.provider === 'zai') {
729
+ const m = normalizeModelId(resolved.model);
730
+ settingsEnv.ANTHROPIC_MODEL = m;
731
+ settingsEnv.ANTHROPIC_DEFAULT_SONNET_MODEL = m;
732
+ settingsEnv.ANTHROPIC_DEFAULT_OPUS_MODEL = m;
733
+ settingsEnv.ANTHROPIC_DEFAULT_HAIKU_MODEL = m;
734
+ settingsEnv.CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC = '1';
735
+ }
689
736
  // For MiniMax: also override all model aliases in settings
690
737
  if (resolved.provider === 'minimax') {
691
738
  settingsEnv.ANTHROPIC_MODEL = resolved.model;
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@exreve/exk",
3
- "version": "1.0.78",
3
+ "version": "1.0.80",
4
4
  "description": "exk - Control Claude CLI with voice and programmable interfaces",
5
5
  "type": "module",
6
6
  "bin": {