colana 1.0.0-beta.40 → 1.0.0-beta.41

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": "colana",
3
- "version": "1.0.0-beta.40",
3
+ "version": "1.0.0-beta.41",
4
4
  "description": "Agent-First. Multiplied. Multi-agent command center for AI coding agents.",
5
5
  "type": "module",
6
6
  "main": "server/index.js",
package/public/app.js CHANGED
@@ -1514,9 +1514,10 @@ async function sendPersonalChatMessage() {
1514
1514
  assistantBubble.className = 'chat-bubble error';
1515
1515
 
1516
1516
  const isAuthError = err.code === 'GATEWAY_AUTH_FAILED' || err.code === 'GATEWAY_AUTH_MISSING';
1517
+ const isTokenError = err.code === 'GATEWAY_TOKEN_MISSING' || err.code === 'GATEWAY_TOKEN_STALE';
1517
1518
 
1518
1519
  if (isAuthError) {
1519
- // Auth-specific error: show actionable message with "Add API Key" button
1520
+ // Provider API key error: show "Add API Key" button
1520
1521
  const msgSpan = document.createElement('span');
1521
1522
  msgSpan.textContent = err.message || 'No valid API key found for your model provider.';
1522
1523
  assistantBubble.appendChild(msgSpan);
@@ -1527,7 +1528,6 @@ async function sendPersonalChatMessage() {
1527
1528
  addKeyBtn.addEventListener('click', (e) => {
1528
1529
  e.preventDefault();
1529
1530
  openSettingsModal();
1530
- // Scroll to Personal AI Agents section after modal opens
1531
1531
  setTimeout(() => {
1532
1532
  const modelSection = document.getElementById('openclaw-model-config');
1533
1533
  if (modelSection) modelSection.scrollIntoView({ behavior: 'smooth', block: 'center' });
@@ -1535,6 +1535,39 @@ async function sendPersonalChatMessage() {
1535
1535
  });
1536
1536
  assistantBubble.appendChild(addKeyBtn);
1537
1537
 
1538
+ if (err.fix) {
1539
+ const fixHint = document.createElement('div');
1540
+ fixHint.className = 'chat-error-fix-hint';
1541
+ fixHint.textContent = err.fix;
1542
+ assistantBubble.appendChild(fixHint);
1543
+ }
1544
+ } else if (isTokenError) {
1545
+ // Gateway token auth error: show "Restart Gateway" button
1546
+ const msgSpan = document.createElement('span');
1547
+ msgSpan.textContent = err.message || 'Gateway authentication failed.';
1548
+ assistantBubble.appendChild(msgSpan);
1549
+
1550
+ const restartBtn = document.createElement('button');
1551
+ restartBtn.className = 'chat-error-action-btn';
1552
+ restartBtn.textContent = 'Restart Gateway';
1553
+ restartBtn.addEventListener('click', async (e) => {
1554
+ e.preventDefault();
1555
+ restartBtn.disabled = true;
1556
+ restartBtn.textContent = 'Restarting...';
1557
+ try {
1558
+ await fetch('/api/personal-agent/restart-gateway', {
1559
+ method: 'POST',
1560
+ headers: getAuthHeaders(),
1561
+ });
1562
+ restartBtn.textContent = 'Restarted — try again';
1563
+ showToast('Gateway restarted. Try sending your message again.', 'success');
1564
+ } catch {
1565
+ restartBtn.textContent = 'Restart Failed';
1566
+ showToast('Gateway restart failed. Open Settings to troubleshoot.', 'error');
1567
+ }
1568
+ });
1569
+ assistantBubble.appendChild(restartBtn);
1570
+
1538
1571
  if (err.fix) {
1539
1572
  const fixHint = document.createElement('div');
1540
1573
  fixHint.className = 'chat-error-fix-hint';
@@ -1,4 +1,4 @@
1
- import { getOpenClawAuthToken, getOpenClawGatewayPort, getOpenClawDefaultModel, isChatCompletionsEnabled, ensureChatCompletionsEnabled, ensureAuthProfile, readAuthStore } from './openclaw-config.js';
1
+ import { getOpenClawAuthToken, getOpenClawGatewayPort, getOpenClawDefaultModel, getOpenClawConfig, isChatCompletionsEnabled, ensureChatCompletionsEnabled, ensureAuthProfile, readAuthStore } from './openclaw-config.js';
2
2
  import { validate, personalChatSchema, openclawModelSetSchema, openclawModelAuthSchema } from './validation.js';
3
3
  import { setSetting } from './settings-store.js';
4
4
  import { restartOpenClawGateway } from './pty-manager.js';
@@ -99,6 +99,15 @@ export function registerPersonalAgentRoutes(app, { sensitiveLimiter }) {
99
99
  const authToken = getOpenClawAuthToken();
100
100
  if (authToken) {
101
101
  headers['Authorization'] = `Bearer ${authToken}`;
102
+ } else {
103
+ // Gateway auth token not found — the gateway will reject with 401.
104
+ // Log config state for diagnosis on fresh installs.
105
+ const cfg = getOpenClawConfig();
106
+ const hasConfig = !!cfg;
107
+ const hasGateway = !!cfg?.gateway;
108
+ const hasAuth = !!cfg?.gateway?.auth;
109
+ const authMode = cfg?.gateway?.auth?.mode || 'none';
110
+ console.warn(`[personal-agent] No gateway auth token found — config:${hasConfig} gateway:${hasGateway} auth:${hasAuth} mode:${authMode}`);
102
111
  }
103
112
 
104
113
  // 60-second timeout
@@ -131,22 +140,47 @@ export function registerPersonalAgentRoutes(app, { sensitiveLimiter }) {
131
140
  }
132
141
  const status = gatewayRes.status;
133
142
 
134
- // For 401, extract provider from current model for actionable guidance
143
+ // For 401, distinguish gateway-level token auth vs model provider key failure
135
144
  if (status === 401) {
145
+ // If we didn't send a gateway auth token, the 401 is almost certainly
146
+ // a gateway token rejection — not a model provider key issue.
147
+ if (!authToken) {
148
+ return res.status(401).json({
149
+ error: 'Gateway authentication failed — no gateway auth token found.',
150
+ code: 'GATEWAY_TOKEN_MISSING',
151
+ fix: 'Restart the gateway in Settings > Personal AI Agents, or run "openclaw onboard" to regenerate the config.',
152
+ });
153
+ }
154
+
155
+ // Token was sent but rejected — could be stale token or provider key issue
136
156
  const currentModel = getOpenClawDefaultModel() || '';
137
157
  const slash = currentModel.indexOf('/');
138
158
  const provider = slash > 0 ? currentModel.substring(0, slash).toLowerCase() : null;
139
159
  const providerLabel = provider || null;
140
160
  const envVar = provider ? PROVIDER_ENV_MAP[provider] : null;
161
+
162
+ // Check if the error body hints at provider-level auth failure
163
+ const isProviderAuth = errText.includes('api_key') || errText.includes('API key')
164
+ || errText.includes('invalid_api_key') || errText.includes('authentication_error');
165
+
166
+ if (isProviderAuth) {
167
+ return res.status(401).json({
168
+ error: providerLabel
169
+ ? `Authentication failed — your ${providerLabel} API key may be missing or invalid.`
170
+ : 'Authentication failed — your API key may be missing or invalid.',
171
+ code: 'GATEWAY_AUTH_FAILED',
172
+ fix: envVar
173
+ ? `Add or update your ${envVar} in Settings > Personal AI Agents.`
174
+ : 'Add your API key in Settings > Personal AI Agents.',
175
+ provider: provider || null,
176
+ });
177
+ }
178
+
179
+ // Default: gateway token mismatch (token exists locally but doesn't match gateway)
141
180
  return res.status(401).json({
142
- error: providerLabel
143
- ? `Authentication failed — your ${providerLabel} API key may be missing or invalid.`
144
- : 'Authentication failed your API key may be missing or invalid.',
145
- code: 'GATEWAY_AUTH_FAILED',
146
- fix: envVar
147
- ? `Add or update your ${envVar} in Settings > Personal AI Agents.`
148
- : `Add your API key in Settings > Personal AI Agents.`,
149
- provider: provider || null,
181
+ error: 'Gateway authentication failed — the auth token may be stale.',
182
+ code: 'GATEWAY_TOKEN_STALE',
183
+ fix: 'Restart the gateway in Settings > Personal AI Agents to resync the auth token.',
150
184
  });
151
185
  }
152
186