managarten/packages/shared-llm/src/errors.ts
Till JS 56065c8537 fix(mana/web): unwrap $state proxy in workbench-scenes Dexie writes
Adding an app to a workbench scene threw DataCloneError. scenesState
is a $state array, so current.openApps was a Svelte 5 proxy and
spreading it into a new array left proxy entries inside; IndexedDB's
structured clone refuses to serialise those. Snapshot before handing
the array to patchScene / createScene so Dexie sees plain objects.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 00:44:00 +02:00

80 lines
2.4 KiB
TypeScript

/**
* Typed error classes for the LLM orchestrator. UI code can `instanceof`
* these to render task-appropriate failure states (retry button, switch
* tier prompt, "blocked by safety filter" notice, etc.).
*/
import type { LlmTier } from './tiers';
export class LlmError extends Error {
constructor(message: string) {
super(message);
this.name = 'LlmError';
}
}
/** No tier from the user's preference list was able to run the task. */
export class NoTierAvailableError extends LlmError {
constructor(
public readonly taskName: string,
public readonly attempted: LlmTier[]
) {
super(`No tier could run task '${taskName}' (attempted: ${attempted.join(', ') || 'none'})`);
this.name = 'NoTierAvailableError';
}
}
/** The user's chosen tier is below the task's declared minimum tier. */
export class TierTooLowError extends LlmError {
constructor(
public readonly taskName: string,
public readonly requiredTier: LlmTier,
public readonly userTier: LlmTier
) {
super(
`Task '${taskName}' requires tier '${requiredTier}' but user is on '${userTier}'. Activate the higher tier in settings.`
);
this.name = 'TierTooLowError';
}
}
/**
* The upstream provider blocked the content (e.g. Gemini safety filter,
* OpenAI moderation). The UI should offer "retry" + "switch to another
* provider" options to the user — this is NOT auto-recoverable because
* a different provider might allow the same content (or might not).
*/
export class ProviderBlockedError extends LlmError {
constructor(
public readonly tier: LlmTier,
public readonly providerMessage: string
) {
super(`Provider '${tier}' blocked the request: ${providerMessage}`);
this.name = 'ProviderBlockedError';
}
}
/** Network/server error from a remote tier (mana-server, cloud). */
export class BackendUnreachableError extends LlmError {
constructor(
public readonly tier: LlmTier,
public readonly httpStatus?: number,
details?: string
) {
super(
`Backend '${tier}' is unreachable${httpStatus ? ` (HTTP ${httpStatus})` : ''}${details ? `: ${details}` : ''}`
);
this.name = 'BackendUnreachableError';
}
}
/**
* The browser tier specifically failed to load — model download
* interrupted, WebGPU adapter request failed, OOM, etc.
*/
export class EdgeLoadFailedError extends LlmError {
constructor(public readonly cause: string) {
super(`Edge LLM failed to load: ${cause}`);
this.name = 'EdgeLoadFailedError';
}
}