mirror of
https://github.com/supermemoryai/claude-supermemory.git
synced 2026-09-14 14:58:03 +08:00
a4ecd312b1
* feat: fail open with 3s network cap on all hooks; async capture; token count in recall banner - All hook API calls hard-capped at 3s (was 15s default, 4s recall); every failure path continues the session with a visible error - Stop/capture hook runs with "async": true — fire-and-forget save, so the user gets their prompt back immediately. Injection hooks stay sync (async hooks' output is discarded, which would kill recall injection and auto-approval); tightened their backstop timeouts - Network failures now say "Supermemory unreachable" instead of raw fetch errors, and session-start no longer claims "no previous memories" when the fetch failed — only a 404 means empty - Recall banner shows the injected context cost: "recalled 5 memories (32 tok)" Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PfsBZgW6vDm8GEcy9ML3dT * feat: statusline tally counts recalled memories in context, not recall events Search state accumulates a cumulative memories counter (fresh injections only); the resting tally shows "9 recalled" instead of "6 recalls". Sessions with only MCP-tool searches (nothing hook-injected) keep the event-count fallback. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PfsBZgW6vDm8GEcy9ML3dT --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
80 lines
2.6 KiB
JavaScript
80 lines
2.6 KiB
JavaScript
/**
|
|
* Shared error utilities for mapping Supermemory SDK errors to user-friendly messages.
|
|
*
|
|
* The SDK (`supermemory` v4.x) attaches a numeric `.status` property to all
|
|
* APIError instances, so we rely on that rather than `instanceof` checks to
|
|
* avoid bundling / import-path issues.
|
|
*/
|
|
|
|
/**
|
|
* Map an SDK error (or any Error) to a concise, actionable message.
|
|
*
|
|
* @param {Error & { status?: number }} err
|
|
* @returns {string}
|
|
*/
|
|
function getUserFriendlyError(err) {
|
|
const status = err?.status;
|
|
|
|
if (
|
|
err?.name === 'TimeoutError' ||
|
|
err?.name === 'AbortError' ||
|
|
err?.message === 'fetch failed'
|
|
) {
|
|
return 'Supermemory unreachable (network) — continuing without memory.';
|
|
}
|
|
if (status === 400) {
|
|
return 'Bad request \u2014 your API key or request format may be invalid. Check your key at https://console.supermemory.ai';
|
|
}
|
|
if (status === 401) {
|
|
return 'Authentication failed \u2014 your API key may be expired or revoked. Re-authenticate with the supermemory login command or check https://console.supermemory.ai';
|
|
}
|
|
if (status === 403) {
|
|
return 'Permission denied \u2014 this feature may require a different Supermemory plan. Check https://supermemory.ai/pricing';
|
|
}
|
|
if (status === 429) {
|
|
return 'Rate limited \u2014 too many requests. Will retry next session.';
|
|
}
|
|
if (typeof status === 'number' && status >= 500) {
|
|
return 'Supermemory service is temporarily unavailable. Will retry next session.';
|
|
}
|
|
|
|
return err?.message || 'Unknown error';
|
|
}
|
|
|
|
/**
|
|
* Should the caller consider retrying this request later?
|
|
*
|
|
* Returns true for rate-limit (429), server errors (5xx), and
|
|
* network/connection errors (no HTTP status at all).
|
|
*
|
|
* @param {Error & { status?: number }} err
|
|
* @returns {boolean}
|
|
*/
|
|
function isRetryableError(err) {
|
|
const status = err?.status;
|
|
if (status === 429) return true;
|
|
if (typeof status === 'number' && status >= 500) return true;
|
|
// Connection / timeout errors have no status
|
|
if (status === undefined || status === null) return true;
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Is this error expected / harmless?
|
|
*
|
|
* 404 means the user simply has no data yet. Connection and timeout errors
|
|
* (no HTTP status) are transient network blips.
|
|
*
|
|
* @param {Error & { status?: number }} err
|
|
* @returns {boolean}
|
|
*/
|
|
function isBenignError(err) {
|
|
const status = err?.status;
|
|
if (status === 404) return true;
|
|
// No status usually means a connection or timeout error
|
|
if (status === undefined || status === null) return true;
|
|
return false;
|
|
}
|
|
|
|
module.exports = { getUserFriendlyError, isRetryableError, isBenignError };
|