Spaces:
Configuration error
Configuration error
File size: 4,097 Bytes
e8a6c67 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 | <script lang="ts">
/**
* v0.4.2 §12 — four canonical error states, each in polite-redirect
* register. Same tone as cold-start: explanatory, helpful, never
* alarming. The card announces via aria-live=assertive; first action
* receives focus (caller wires `bind:focusEl` if needed).
*/
import type { Tier } from '$lib/types/tier';
import type { ErrorKey } from '$lib/types/states';
import TierGlyph from '$lib/components/glyphs/TierGlyph.svelte';
interface Action {
label: string;
onClick?: () => void;
href?: string;
}
interface Props {
state: ErrorKey;
actions?: Action[];
/** Override headline / body for context-specific messages. */
eyebrowOverride?: string;
headlineOverride?: string;
bodyOverride?: string;
}
let {
state,
actions,
eyebrowOverride,
headlineOverride,
bodyOverride
}: Props = $props();
interface Spec {
eyebrow: string;
headline: string;
body: string;
tier: Tier;
defaultActions: string[];
}
const SPECS: Record<ErrorKey, Spec> = {
geocoder: {
eyebrow: 'Address not resolved',
headline: "We couldn't resolve that to a NYC address.",
body:
'Try a more specific street address — for example, "80 Pioneer Street, Brooklyn." Riprap covers the five boroughs only; international addresses, NJ addresses, and points outside NYC aren\'t supported.',
tier: 'proxy',
defaultActions: ['Use a sample query', 'Edit query']
},
'all-silent': {
eyebrow: 'Outside evidence coverage',
headline: 'No specialists found evidence at this point.',
body:
'The address resolved, but every flood-evidence specialist returned silent. This is rare and usually means parkland, water, or a point with no nearby 311, no FloodNet sensor, and no Sandy overlap. Try a nearby street address or expand to neighborhood-mode.',
tier: 'proxy',
defaultActions: ['Try nearby address', 'Switch to neighborhood-mode']
},
grounding: {
eyebrow: 'Grounding failure',
headline: "Briefing prose couldn't be composed within citation constraints.",
body:
'Mellea rejected all reroll attempts. The underlying evidence is fine — only the prose composition failed. Download the structured evidence below, or contact support.',
tier: 'modeled',
defaultActions: ['Download evidence (JSON)', 'Contact support', 'Try again']
},
backend: {
eyebrow: 'Backend unavailable',
headline: 'All routing targets exhausted.',
body:
"LiteLLM tried Local Ollama → HF Space T4 → AMD MI300X and didn't reach a healthy backend. This usually clears within 5 minutes during a deploy window. The hardware-pill in the header is currently red.",
tier: 'proxy',
defaultActions: ['Retry now', 'Switch backend']
}
};
let spec = $derived(SPECS[state]);
let resolvedActions = $derived<Action[]>(
actions ?? spec.defaultActions.map((label) => ({ label }))
);
</script>
<article class="error-card error-card-{state}" role="alert" aria-live="assertive">
<header class="error-card-head">
<TierGlyph tier={spec.tier} size={11} color="var(--tier-{spec.tier})" />
<span class="error-card-eyebrow">{eyebrowOverride ?? spec.eyebrow}</span>
</header>
<h3 class="error-card-headline">{headlineOverride ?? spec.headline}</h3>
<p class="error-card-body">{bodyOverride ?? spec.body}</p>
<div class="error-card-actions">
{#each resolvedActions as a, i (i)}
{#if a.href}
<a class="error-card-action" class:is-primary={i === 0} href={a.href}>{a.label}</a>
{:else}
<button
type="button"
class="error-card-action"
class:is-primary={i === 0}
onclick={a.onClick}
>{a.label}</button>
{/if}
{/each}
</div>
<footer class="error-card-foot">
<span class="section-label">Trust signals · still on</span>
<span class="error-card-foot-copy">All foundation models Apache-2.0 · No commercial APIs at runtime</span>
</footer>
</article>
|