diff options
| -rw-r--r-- | main.html | 6 | ||||
| -rw-r--r-- | modules/core/core-bundle.js | 51 | ||||
| -rw-r--r-- | modules/core/module-billing.js | 2 | ||||
| -rw-r--r-- | modules/core/module-loader.js | 2 |
4 files changed, 43 insertions, 18 deletions
@@ -1349,13 +1349,13 @@ </script> <!-- v4.5.63: A2A scratchpad fixes + agent-register arg fix --> -<script src="modules/core/core-bundle.js?v=v4.6.135"></script> +<script src="modules/core/core-bundle.js?v=v4.6.136"></script> <!-- Async dependency-ordered module loader now only initializes terminal and loads optional ext modules --> -<script src="modules/core/module-loader.js?v=v4.6.135"></script> +<script src="modules/core/module-loader.js?v=v4.6.136"></script> <!-- Critical ext bundle loads AFTER webx11 exists so registerModule calls work --> -<script src="modules/ext/critical-ext-bundle.js?v=v4.6.135"></script> +<script src="modules/ext/critical-ext-bundle.js?v=v4.6.136"></script> <script> // ═══ ONE TRUE VERSION SOURCE ═══ diff --git a/modules/core/core-bundle.js b/modules/core/core-bundle.js index 07609e3..e845903 100644 --- a/modules/core/core-bundle.js +++ b/modules/core/core-bundle.js @@ -1237,6 +1237,31 @@ window.VirtualFileSystem = VirtualFileSystem; // Refactored to support multiple LLM providers with auto-fallback // Class name kept as OllamaManager for backward compatibility class OllamaManager { + + async _httpError(response) { + // Surface what the server actually said. "HTTP 429" tells the user nothing; the body + // carries e.g. "Demo limit reached. Login or sign up for more." (2026-10-28) + let detail = ''; + try { + const text = await response.text(); + if (text) { + try { + const j = JSON.parse(text); + detail = (j && (j.error || j.message)) || ''; + if (j && j.needed_usd != null && j.balance_usd != null) { + detail += ` (balance $${j.balance_usd}, need $${j.needed_usd})`; + } + } catch (_) { + detail = text.slice(0, 200); + } + } + } catch (_) { /* body unreadable or already consumed */ } + if (/^\s*</.test(detail)) detail = ''; // an HTML error page is not a message + const err = new Error(detail ? `${detail} (HTTP ${response.status})` : `HTTP ${response.status}`); + err.status = response.status; + return err; + } + constructor(terminal) { this.terminal = terminal; // --- Backward-compat properties (reflected from active provider) --- @@ -1496,7 +1521,7 @@ class OllamaManager { const response = await fetch(`${ep}/api/tags`, { method: 'GET', headers: { 'Content-Type': 'application/json' } }); - if (!response.ok) throw new Error(`HTTP ${response.status}`); + if (!response.ok) throw await this._httpError(response); const data = await response.json(); this.models = data.models || []; this.connected = true; @@ -1533,7 +1558,7 @@ class OllamaManager { const response = await fetch(`${provider.endpoint}/v1/models`, { method: 'GET', headers }); - if (!response.ok) throw new Error(`HTTP ${response.status}`); + if (!response.ok) throw await this._httpError(response); const data = await response.json(); this.models = (data.data || data.models || []).map(m => ({ name: m.id || m.name, @@ -1571,7 +1596,7 @@ class OllamaManager { const response = await fetch(`${ep}/api/tags`, { method: 'GET', headers: { 'Content-Type': 'application/json' } }); - if (!response.ok) throw new Error(`HTTP ${response.status}`); + if (!response.ok) throw await this._httpError(response); const data = await response.json(); this.models = data.models || []; this.connected = true; @@ -1727,7 +1752,7 @@ class OllamaManager { body: JSON.stringify({ model: useModel, prompt: prompt, stream: this.streamEnabled, options: this._ollamaOptions() }), signal }); - if (!response.ok) throw new Error(`HTTP ${response.status}`); + if (!response.ok) throw await this._httpError(response); if (this.streamEnabled) { const reader = response.body.getReader(); @@ -1784,7 +1809,7 @@ class OllamaManager { }), signal }); - if (!response.ok) throw new Error(`HTTP ${response.status}`); + if (!response.ok) throw await this._httpError(response); if (this.streamEnabled) { const reader = response.body.getReader(); @@ -1897,7 +1922,7 @@ class OllamaManager { body: JSON.stringify({ model: useModel, prompt: prompt, stream: this.streamEnabled, options: this._ollamaOptions() }), signal }); - if (!response.ok) throw new Error(`HTTP ${response.status}`); + if (!response.ok) throw await this._httpError(response); let fullResponse = ''; if (this.streamEnabled) { @@ -1960,7 +1985,7 @@ class OllamaManager { }), signal }); - if (!response.ok) throw new Error(`HTTP ${response.status}`); + if (!response.ok) throw await this._httpError(response); let fullResponse = ''; if (this.streamEnabled) { @@ -2085,7 +2110,7 @@ class OllamaManager { if (response.status === 400) { return await this.chatWithToolsFallback(messages, tools, useModel, signal); } - throw new Error(`HTTP ${response.status}`); + throw await this._httpError(response); } const data = await response.json(); this.terminal.log('INFO', 'Ollama', `chatWithTools round-trip: ${networkTime}s (model: ${useModel}, provider: ${provider.name})`); @@ -2135,7 +2160,7 @@ class OllamaManager { }); const networkTime = Math.round((Date.now() - t0) / 1000); if (!response.ok) { - throw new Error(`HTTP ${response.status}`); + throw await this._httpError(response); } const data = await response.json(); this.terminal.log('INFO', 'Ollama', `chatWithTools round-trip: ${networkTime}s (model: ${useModel}, provider: ${provider.name})`); @@ -2274,7 +2299,7 @@ class OllamaManager { body: JSON.stringify(body), signal }); - if (!response.ok) throw new Error(`HTTP ${response.status}`); + if (!response.ok) throw await this._httpError(response); const data = await response.json(); const text = data.choices?.[0]?.message?.content || ''; const latency = Date.now() - t0; @@ -2310,7 +2335,7 @@ Only output XML function calls for tool tasks. If no tool is needed, answer norm method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body), signal }); - if (!response.ok) throw new Error(`HTTP ${response.status}`); + if (!response.ok) throw await this._httpError(response); const data = await response.json(); const text = (data.message?.content || '').trim(); const latency = Date.now() - t0; @@ -2361,7 +2386,7 @@ Only output XML function calls for tool tasks. If no tool is needed, answer norm body: JSON.stringify(body), signal }); - if (!response.ok) throw new Error(`HTTP ${response.status}`); + if (!response.ok) throw await this._httpError(response); const data = await response.json(); const text = data.message?.content || data.response || ''; const latency = Date.now() - t0; @@ -7817,7 +7842,7 @@ class BillingModule { if (bal && bal.plan_allowance) { const pa = bal.plan_allowance; - p(`🎁 Included usage (${pa.plan}): $${Number(pa.used_usd).toFixed(2)} of $${Number(pa.limit_usd).toFixed(2)} this month — $${Number(pa.remaining_usd).toFixed(2)} left, then your balance pays`, 'info'); + p(`🎁 Included usage (${pa.plan}): $${Number(pa.used_usd).toFixed(2)} of $${Number(pa.limit_usd).toFixed(2)} ${pa.period === 'day' ? 'today' : 'this month'} — $${Number(pa.remaining_usd).toFixed(2)} left, then your balance pays`, 'info'); } if (s && s.msgs) { diff --git a/modules/core/module-billing.js b/modules/core/module-billing.js index b353e79..87f8dc3 100644 --- a/modules/core/module-billing.js +++ b/modules/core/module-billing.js @@ -142,7 +142,7 @@ class BillingModule { if (bal && bal.plan_allowance) { const pa = bal.plan_allowance; - p(`🎁 Included usage (${pa.plan}): $${Number(pa.used_usd).toFixed(2)} of $${Number(pa.limit_usd).toFixed(2)} this month — $${Number(pa.remaining_usd).toFixed(2)} left, then your balance pays`, 'info'); + p(`🎁 Included usage (${pa.plan}): $${Number(pa.used_usd).toFixed(2)} of $${Number(pa.limit_usd).toFixed(2)} ${pa.period === 'day' ? 'today' : 'this month'} — $${Number(pa.remaining_usd).toFixed(2)} left, then your balance pays`, 'info'); } if (s && s.msgs) { diff --git a/modules/core/module-loader.js b/modules/core/module-loader.js index 52cee36..0cc4dd2 100644 --- a/modules/core/module-loader.js +++ b/modules/core/module-loader.js @@ -4,7 +4,7 @@ // Core module bundle loaded synchronously in main.html. // This loader only handles version cache-busting, splash, terminal init, and optional ext modules. - const LATEST_VER = 'v4.6.135'; + const LATEST_VER = 'v4.6.136'; const CACHE = '?v=' + LATEST_VER; // Exposed so ext modules can register their own URL with the same cache-busting version // instead of an unversioned path the browser may already have cached (shell.js did). |