@axplusb/kepler 2.3.1 → 2.3.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@axplusb/kepler",
3
- "version": "2.3.1",
3
+ "version": "2.3.2",
4
4
  "description": "Kepler — AI coding agent with operating brief, preflight planning, and sub-agents. SWE-bench Lite evaluated.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -0,0 +1,287 @@
1
+ function compact(value) {
2
+ return String(value || '').trim();
3
+ }
4
+
5
+ function lower(value) {
6
+ return compact(value).toLowerCase();
7
+ }
8
+
9
+ const PROVIDER_ALIASES = new Map([
10
+ ['openrouter', 'openrouter'],
11
+ ['openrouterv2', 'openrouter'],
12
+ ['openroutergateway', 'openrouter'],
13
+ ['openrouterv2gateway', 'openrouter'],
14
+ ['anthropic', 'anthropic'],
15
+ ['claude', 'anthropic'],
16
+ ['claudegateway', 'anthropic'],
17
+ ['openai', 'openai'],
18
+ ['openaigateway', 'openai'],
19
+ ['google', 'googleai'],
20
+ ['googleai', 'googleai'],
21
+ ['googlegateway', 'googleai'],
22
+ ['googleaigateway', 'googleai'],
23
+ ['gemini', 'googleai'],
24
+ ['azure', 'azureopenai'],
25
+ ['azureopenai', 'azureopenai'],
26
+ ['azureopenaigateway', 'azureopenai'],
27
+ ['bedrock', 'bedrock'],
28
+ ['aws', 'bedrock'],
29
+ ['bedrockgateway', 'bedrock'],
30
+ ['databricks', 'databricks'],
31
+ ['databricksgateway', 'databricks'],
32
+ ['custom', 'custom'],
33
+ ['byom', 'custom'],
34
+ ['openai-compatible', 'custom'],
35
+ ['deepseek', 'deepseek'],
36
+ ['deepseekgateway', 'deepseek'],
37
+ ['dashscope', 'dashscope'],
38
+ ['dashscopegateway', 'dashscope'],
39
+ ['qwen', 'dashscope'],
40
+ ['zhipu', 'zhipu'],
41
+ ['zhipugateway', 'zhipu'],
42
+ ['glm', 'zhipu'],
43
+ ['moonshot', 'moonshot'],
44
+ ['moonshotgateway', 'moonshot'],
45
+ ['kimi', 'moonshot'],
46
+ ['xai', 'xai'],
47
+ ['xaigateway', 'xai'],
48
+ ['grok', 'xai'],
49
+ ['mistral', 'mistral'],
50
+ ['mistralgateway', 'mistral'],
51
+ ]);
52
+
53
+ const PROVIDER_GUIDANCE = {
54
+ openrouter: {
55
+ label: 'OpenRouter',
56
+ lines: [
57
+ 'Check that your OpenRouter API key is saved and has enough credits/quota.',
58
+ 'Verify the selected model is available on OpenRouter and that provider routing is allowed for it.',
59
+ 'If settings were just updated, run /login or restart the CLI so provider settings sync again.',
60
+ ],
61
+ },
62
+ anthropic: {
63
+ label: 'Anthropic',
64
+ lines: [
65
+ 'Check that your Anthropic API key is saved and active.',
66
+ 'Verify the selected Claude model is enabled for your Anthropic account and region.',
67
+ 'If settings were just updated, run /login or restart the CLI so provider settings sync again.',
68
+ ],
69
+ },
70
+ openai: {
71
+ label: 'OpenAI',
72
+ lines: [
73
+ 'Check that your OpenAI API key is saved and has access to the selected model.',
74
+ 'Verify project billing, model permissions, and rate limits in your OpenAI account.',
75
+ 'If settings were just updated, run /login or restart the CLI so provider settings sync again.',
76
+ ],
77
+ },
78
+ googleai: {
79
+ label: 'Google AI',
80
+ lines: [
81
+ 'Check that your Google AI API key is saved and active.',
82
+ 'Verify the selected Gemini model is available for that key and region.',
83
+ 'If settings were just updated, run /login or restart the CLI so provider settings sync again.',
84
+ ],
85
+ },
86
+ azureopenai: {
87
+ label: 'Azure OpenAI',
88
+ lines: [
89
+ 'Check that Azure OpenAI API key, endpoint, API version, and deployment/model name are saved.',
90
+ 'Verify the deployment exists in Azure AI Foundry and the key has access to that resource.',
91
+ 'If settings were just updated, run /login or restart the CLI so provider settings sync again.',
92
+ ],
93
+ },
94
+ bedrock: {
95
+ label: 'AWS Bedrock',
96
+ lines: [
97
+ 'Check that AWS Access Key ID, Secret Access Key, optional Session Token, and Region are saved.',
98
+ 'Verify the IAM principal can call bedrock-runtime:InvokeModel for the selected model and region.',
99
+ 'If settings were just updated, run /login or restart the CLI so provider settings sync again.',
100
+ ],
101
+ },
102
+ databricks: {
103
+ label: 'Databricks',
104
+ lines: [
105
+ 'Check that your Databricks host/workspace URL and token are saved.',
106
+ 'Verify the selected serving endpoint exists and the token can query it.',
107
+ 'If settings were just updated, run /login or restart the CLI so provider settings sync again.',
108
+ ],
109
+ },
110
+ custom: {
111
+ label: 'custom OpenAI-compatible provider',
112
+ lines: [
113
+ 'Check that base URL, API key, and model name are saved for the custom provider.',
114
+ 'Verify the endpoint supports OpenAI-compatible chat completions for the selected model.',
115
+ 'If settings were just updated, run /login or restart the CLI so provider settings sync again.',
116
+ ],
117
+ },
118
+ deepseek: {
119
+ label: 'DeepSeek',
120
+ lines: [
121
+ 'Check that your DeepSeek API key is saved and active.',
122
+ 'Verify the selected DeepSeek model is available and your account has quota.',
123
+ 'If settings were just updated, run /login or restart the CLI so provider settings sync again.',
124
+ ],
125
+ },
126
+ dashscope: {
127
+ label: 'DashScope/Qwen',
128
+ lines: [
129
+ 'Check that your DashScope API key is saved and active.',
130
+ 'Verify the selected Qwen model is available for your account and region.',
131
+ 'If settings were just updated, run /login or restart the CLI so provider settings sync again.',
132
+ ],
133
+ },
134
+ zhipu: {
135
+ label: 'Zhipu/GLM',
136
+ lines: [
137
+ 'Check that your Zhipu API key is saved and active.',
138
+ 'Verify the selected GLM model is enabled and your account has quota.',
139
+ 'If settings were just updated, run /login or restart the CLI so provider settings sync again.',
140
+ ],
141
+ },
142
+ moonshot: {
143
+ label: 'Moonshot/Kimi',
144
+ lines: [
145
+ 'Check that your Moonshot API key is saved and active.',
146
+ 'Verify the selected Kimi model is enabled and your account has quota.',
147
+ 'If settings were just updated, run /login or restart the CLI so provider settings sync again.',
148
+ ],
149
+ },
150
+ xai: {
151
+ label: 'xAI',
152
+ lines: [
153
+ 'Check that your xAI API key is saved and active.',
154
+ 'Verify the selected Grok model is enabled and your account has quota.',
155
+ 'If settings were just updated, run /login or restart the CLI so provider settings sync again.',
156
+ ],
157
+ },
158
+ mistral: {
159
+ label: 'Mistral',
160
+ lines: [
161
+ 'Check that your Mistral API key is saved and active.',
162
+ 'Verify the selected Mistral model is enabled and your account has quota.',
163
+ 'If settings were just updated, run /login or restart the CLI so provider settings sync again.',
164
+ ],
165
+ },
166
+ };
167
+
168
+ export function isBedrockMissingCredentials(data = {}) {
169
+ const haystack = [
170
+ data.message,
171
+ data.error,
172
+ data.code,
173
+ data.phase,
174
+ data.provider,
175
+ data.gateway,
176
+ data.gateway_type,
177
+ data.exception_type,
178
+ ].map(lower).join(' ');
179
+
180
+ const mentionsBedrock = haystack.includes('bedrock');
181
+ const mentionsAwsCreds = haystack.includes('aws credentials')
182
+ || haystack.includes('aws credential')
183
+ || haystack.includes('aws_access_key')
184
+ || haystack.includes('aws_secret')
185
+ || haystack.includes('access key')
186
+ || haystack.includes('secret access key');
187
+
188
+ return mentionsBedrock && mentionsAwsCreds;
189
+ }
190
+
191
+ export function normalizeGatewayProvider(data = {}) {
192
+ const direct = [
193
+ data.provider,
194
+ data.gateway,
195
+ data.gateway_type,
196
+ data.gatewayType,
197
+ ].map(normalizeProviderToken).find(Boolean);
198
+ if (direct) return direct;
199
+
200
+ const haystack = [
201
+ data.message,
202
+ data.error,
203
+ data.code,
204
+ data.phase,
205
+ data.operation,
206
+ data.exception_type,
207
+ data.model,
208
+ ].map(lower).join(' ');
209
+
210
+ for (const [alias, provider] of PROVIDER_ALIASES.entries()) {
211
+ if (haystack.includes(alias)) return provider;
212
+ }
213
+ return '';
214
+ }
215
+
216
+ export function formatAgentErrorGuidance(data = {}) {
217
+ const message = compact(data.message || data.error || 'Agent execution failed.');
218
+ const code = compact(data.code);
219
+ const phase = compact(data.phase);
220
+ const provider = normalizeGatewayProvider(data);
221
+ const providerMeta = provider || compact(data.provider || data.gateway || data.gateway_type);
222
+ const taskId = compact(data.task_id);
223
+ const retryAfter = data.retry_after != null ? compact(data.retry_after) : '';
224
+ const retryable = data.retryable === true;
225
+
226
+ if (isBedrockMissingCredentials(data)) {
227
+ return {
228
+ title: 'AWS Bedrock credentials are missing.',
229
+ lines: [
230
+ 'Kepler reached the Bedrock gateway, but the backend did not receive AWS Access Key ID and Secret Access Key.',
231
+ 'Open Kepler/AppStak model settings, re-save the AWS Bedrock provider with Access Key ID, Secret Access Key, and Region, then retry.',
232
+ 'If settings were just updated, run /login or restart the CLI so provider settings sync again.',
233
+ ],
234
+ meta: buildMeta({ code, phase, provider: provider || 'bedrock', taskId, retryAfter, retryable }),
235
+ };
236
+ }
237
+
238
+ const lines = [];
239
+ const providerGuidance = PROVIDER_GUIDANCE[provider];
240
+ if (phase === 'gateway' || code.includes('gateway')) {
241
+ const label = providerGuidance?.label || 'provider';
242
+ lines.push(`The ${label} gateway failed before the agent could respond.`);
243
+ if (providerGuidance) {
244
+ lines.push(...providerGuidance.lines);
245
+ } else {
246
+ lines.push('Check the selected provider, model, and BYOK credentials in settings, then retry.');
247
+ }
248
+ } else if (/authentication|token/i.test(message)) {
249
+ lines.push('Run /login to re-authenticate.');
250
+ } else if (/api key|openrouter/i.test(message)) {
251
+ lines.push('Run /config to set up or refresh your provider settings.');
252
+ } else if (/backend|network/i.test(message)) {
253
+ lines.push('Check that the backend is reachable, then retry.');
254
+ }
255
+
256
+ if (retryable && retryAfter) {
257
+ lines.push(`This looks retryable after ${retryAfter}s.`);
258
+ } else if (retryable) {
259
+ lines.push('This looks retryable.');
260
+ }
261
+
262
+ return {
263
+ title: message,
264
+ lines,
265
+ meta: buildMeta({ code, phase, provider: providerMeta, taskId, retryAfter, retryable }),
266
+ };
267
+ }
268
+
269
+ function normalizeProviderToken(value) {
270
+ const raw = lower(value);
271
+ if (!raw) return '';
272
+ const compacted = raw.replace(/[^a-z0-9]/g, '');
273
+ return PROVIDER_ALIASES.get(raw)
274
+ || PROVIDER_ALIASES.get(compacted)
275
+ || '';
276
+ }
277
+
278
+ function buildMeta({ code, phase, provider, taskId, retryAfter, retryable }) {
279
+ const parts = [];
280
+ if (provider) parts.push(`provider=${provider}`);
281
+ if (phase) parts.push(`phase=${phase}`);
282
+ if (code) parts.push(`code=${code}`);
283
+ if (retryable) parts.push(`retryable=true`);
284
+ if (retryAfter) parts.push(`retry_after=${retryAfter}s`);
285
+ if (taskId) parts.push(`task=${taskId}`);
286
+ return parts;
287
+ }
@@ -40,6 +40,7 @@ import { TarangAuth } from '../auth/tarang-auth.mjs';
40
40
  import { ApprovalManager } from '../core/approval.mjs';
41
41
  import { resolveBackendUrl } from '../core/backend-url.mjs';
42
42
  import { formatMessageWindow, lowWindowStatus, messagesRemaining } from '../core/rate-limit-display.mjs';
43
+ import { formatAgentErrorGuidance } from '../core/error-guidance.mjs';
43
44
  import { BUILTIN_AGENTS, runAgent } from './agents.mjs';
44
45
  import { SessionManager } from '../core/session-manager.mjs';
45
46
  import { parseArgs } from '../config/cli-args.mjs';
@@ -1908,9 +1909,15 @@ function renderEvent(event) {
1908
1909
  case 'error':
1909
1910
  stopSpinner();
1910
1911
  flushContent();
1911
- process.stderr.write(`\n ${c.red('✗')} ${data?.message || 'Unknown error'}\n`);
1912
- if ((data?.message || '').includes('Authentication')) {
1913
- process.stderr.write(` ${c.dim('Run /login to re-authenticate')}\n`);
1912
+ {
1913
+ const guidance = formatAgentErrorGuidance(data || {});
1914
+ process.stderr.write(`\n ${c.red('')} ${guidance.title}\n`);
1915
+ for (const line of guidance.lines) {
1916
+ process.stderr.write(` ${c.dim(line)}\n`);
1917
+ }
1918
+ if (guidance.meta.length) {
1919
+ process.stderr.write(` ${c.dim(guidance.meta.join(' · '))}\n`);
1920
+ }
1914
1921
  }
1915
1922
  break;
1916
1923
 
@@ -10,6 +10,7 @@
10
10
 
11
11
  import { toolDisplayLabel, toolDisplaySummary } from '../terminal/tool-display.mjs';
12
12
  import { formatMessageWindow } from '../core/rate-limit-display.mjs';
13
+ import { formatAgentErrorGuidance } from '../core/error-guidance.mjs';
13
14
 
14
15
  const RESET = '\x1b[0m';
15
16
  const BOLD = '\x1b[1m';
@@ -309,16 +310,13 @@ export class EventFormatter {
309
310
  }
310
311
 
311
312
  _error(data) {
312
- const msg = data?.message || 'Unknown error';
313
- process.stderr.write(`\n ${RED}✗ ${msg}${RESET}\n`);
314
-
315
- // Helpful suggestions for common errors
316
- if (msg.includes('Authentication') || msg.includes('token')) {
317
- process.stderr.write(` ${DIM}Run /login to re-authenticate${RESET}\n`);
318
- } else if (msg.includes('API key') || msg.includes('OpenRouter')) {
319
- process.stderr.write(` ${DIM}Run /config to set up your provider${RESET}\n`);
320
- } else if (msg.includes('Backend') || msg.includes('Network')) {
321
- process.stderr.write(` ${DIM}Check if the backend is running at ${this.sessionInfo?.backend || 'localhost:8150'}${RESET}\n`);
313
+ const guidance = formatAgentErrorGuidance(data || {});
314
+ process.stderr.write(`\n ${RED}✗ ${guidance.title}${RESET}\n`);
315
+ for (const line of guidance.lines) {
316
+ process.stderr.write(` ${DIM}${line}${RESET}\n`);
317
+ }
318
+ if (guidance.meta.length) {
319
+ process.stderr.write(` ${DIM}${guidance.meta.join(' · ')}${RESET}\n`);
322
320
  }
323
321
  }
324
322