Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 9 additions & 12 deletions apps/runtime/resilience.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,7 @@ const IGNORABLE_ERRORS = [
];

function isIgnorable(err: unknown): boolean {
const msg =
err instanceof Error ? `${err.name}: ${err.message}` : String(err);
const msg = err instanceof Error ? `${err.name}: ${err.message}` : String(err);
if (IGNORABLE_ERRORS.some((token) => msg.includes(token))) return true;
// Check cause chain (Node.js fetch wraps network errors)
if (err instanceof Error && err.cause) {
Expand Down Expand Up @@ -93,17 +92,17 @@ function gracefulShutdown() {
if (shuttingDown) return;
shuttingDown = true;
for (const cb of shutdownCallbacks) {
try { cb(); } catch (e) { console.error("[shutdown] callback error", e); }
try {
cb();
} catch (e) {
console.error("[shutdown] callback error", e);
}
}

const mem = process.memoryUsage();
const heapMb = Math.round(mem.heapUsed / 1024 / 1024);
console.warn(
`[memory] Heap at ${heapMb}MB — initiating graceful shutdown to avoid OOM crash`,
);
console.warn(
`[memory] Draining in-flight requests for ${GRACEFUL_DRAIN_MS}ms before exit…`,
);
console.warn(`[memory] Heap at ${heapMb}MB — initiating graceful shutdown to avoid OOM crash`);
console.warn(`[memory] Draining in-flight requests for ${GRACEFUL_DRAIN_MS}ms before exit…`);

// Give in-flight requests a few seconds to complete, then exit cleanly.
// Render will restart the instance automatically.
Expand All @@ -124,9 +123,7 @@ setInterval(() => {
}

if (rssMb > MEMORY_WARN_THRESHOLD_MB) {
console.warn(
`[memory] WARNING RSS=${rssMb}MB heap=${heapMb}MB — approaching limit`,
);
console.warn(`[memory] WARNING RSS=${rssMb}MB heap=${heapMb}MB — approaching limit`);
if (global.gc) {
console.warn("[memory] Forcing garbage collection");
global.gc();
Expand Down
23 changes: 13 additions & 10 deletions apps/ui/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,22 @@ import { useChatKit } from "@/components/chat/chat-kit";
import { s } from "@hashbrownai/core";
import { chatTheme } from "@/lib/chat-theme";
import { useInitialSuggestions } from "./lib/suggestions";
import { StyleProvider } from "@/lib/style-context";

export function App() {
return (
<CopilotKit
runtimeUrl={
import.meta.env.VITE_RUNTIME_HOST
? `https://${import.meta.env.VITE_RUNTIME_HOST}.onrender.com/api/copilotkit`
: "/api/copilotkit"
}
showDevConsole={false}
>
<Page />
</CopilotKit>
<StyleProvider>
<CopilotKit
runtimeUrl={
import.meta.env.VITE_RUNTIME_HOST
? `https://${import.meta.env.VITE_RUNTIME_HOST}.onrender.com/api/copilotkit`
: "/api/copilotkit"
}
showDevConsole={false}
>
<Page />
</CopilotKit>
</StyleProvider>
);
}

Expand Down
17 changes: 17 additions & 0 deletions apps/ui/src/components/app-header.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import { useStyle } from "@/lib/style-context";

export function AppHeader({ title }: { title: string }) {
const { style, setStyle } = useStyle();

return (
<header className="relative flex items-center justify-between px-6 py-4">
<h1
Expand All @@ -16,6 +20,19 @@ export function AppHeader({ title }: { title: string }) {
<span aria-hidden="true" className="mx-0.5 inline-block h-5 w-px bg-[var(--input)]" />
{title}
</h1>
<button
type="button"
onClick={() => setStyle(style === "default" ? "luma" : "default")}
className="inline-flex items-center gap-1.5 rounded-full border border-[var(--border)] bg-[var(--surface)] px-3 py-1.5 text-xs font-medium text-[var(--foreground)] transition-colors hover:bg-[var(--muted)]"
>
<span
className="inline-block size-2 rounded-full"
style={{
backgroundColor: style === "luma" ? "var(--sunshine-yellow)" : "var(--sky-blue)",
}}
/>
{style === "luma" ? "Luma" : "Default"}
</button>
<div
className="absolute bottom-0 left-6 right-6 h-px"
style={{
Expand Down
62 changes: 62 additions & 0 deletions apps/ui/src/components/ui-default/accordion.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import * as React from "react";
import { ChevronDownIcon } from "lucide-react";
import { Accordion as AccordionPrimitive } from "radix-ui";

import { cn } from "@/lib/utils";

function Accordion({ ...props }: React.ComponentProps<typeof AccordionPrimitive.Root>) {
return <AccordionPrimitive.Root data-slot="accordion" {...props} />;
}

function AccordionItem({
className,
...props
}: React.ComponentProps<typeof AccordionPrimitive.Item>) {
return (
<AccordionPrimitive.Item
data-slot="accordion-item"
className={cn("border-b last:border-b-0", className)}
{...props}
/>
);
}

function AccordionTrigger({
className,
children,
...props
}: React.ComponentProps<typeof AccordionPrimitive.Trigger>) {
return (
<AccordionPrimitive.Header className="flex">
<AccordionPrimitive.Trigger
data-slot="accordion-trigger"
className={cn(
"focus-visible:border-ring focus-visible:ring-ring/50 flex flex-1 items-start justify-between gap-4 rounded-md py-4 text-left text-sm font-medium transition-all outline-none hover:underline focus-visible:ring-[3px] disabled:pointer-events-none disabled:opacity-50 [&[data-state=open]>svg]:rotate-180",
className,
)}
{...props}
>
{children}
<ChevronDownIcon className="text-muted-foreground pointer-events-none size-4 shrink-0 translate-y-0.5 transition-transform duration-200" />
</AccordionPrimitive.Trigger>
</AccordionPrimitive.Header>
);
}

function AccordionContent({
className,
children,
...props
}: React.ComponentProps<typeof AccordionPrimitive.Content>) {
return (
<AccordionPrimitive.Content
data-slot="accordion-content"
className="data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down overflow-hidden text-sm"
{...props}
>
<div className={cn("pt-0 pb-4", className)}>{children}</div>
</AccordionPrimitive.Content>
);
}

export { Accordion, AccordionItem, AccordionTrigger, AccordionContent };
179 changes: 179 additions & 0 deletions apps/ui/src/components/ui-default/alert-dialog.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
"use client";

import * as React from "react";
import { AlertDialog as AlertDialogPrimitive } from "radix-ui";

import { cn } from "@/lib/utils";
import { Button } from "@/components/ui/button";

function AlertDialog({ ...props }: React.ComponentProps<typeof AlertDialogPrimitive.Root>) {
return <AlertDialogPrimitive.Root data-slot="alert-dialog" {...props} />;
}

function AlertDialogTrigger({
...props
}: React.ComponentProps<typeof AlertDialogPrimitive.Trigger>) {
return <AlertDialogPrimitive.Trigger data-slot="alert-dialog-trigger" {...props} />;
}

function AlertDialogPortal({ ...props }: React.ComponentProps<typeof AlertDialogPrimitive.Portal>) {
return <AlertDialogPrimitive.Portal data-slot="alert-dialog-portal" {...props} />;
}

function AlertDialogOverlay({
className,
...props
}: React.ComponentProps<typeof AlertDialogPrimitive.Overlay>) {
return (
<AlertDialogPrimitive.Overlay
data-slot="alert-dialog-overlay"
className={cn(
"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50",
className,
)}
{...props}
/>
);
}

function AlertDialogContent({
className,
size = "default",
...props
}: React.ComponentProps<typeof AlertDialogPrimitive.Content> & {
size?: "default" | "sm";
}) {
return (
<AlertDialogPortal>
<AlertDialogOverlay />
<AlertDialogPrimitive.Content
data-slot="alert-dialog-content"
data-size={size}
className={cn(
"bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 group/alert-dialog-content fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 data-[size=sm]:max-w-xs data-[size=default]:sm:max-w-lg",
className,
)}
{...props}
/>
</AlertDialogPortal>
);
}

function AlertDialogHeader({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="alert-dialog-header"
className={cn(
"grid grid-rows-[auto_1fr] place-items-center gap-1.5 text-center has-data-[slot=alert-dialog-media]:grid-rows-[auto_auto_1fr] has-data-[slot=alert-dialog-media]:gap-x-6 sm:group-data-[size=default]/alert-dialog-content:place-items-start sm:group-data-[size=default]/alert-dialog-content:text-left sm:group-data-[size=default]/alert-dialog-content:has-data-[slot=alert-dialog-media]:grid-rows-[auto_1fr]",
className,
)}
{...props}
/>
);
}

function AlertDialogFooter({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="alert-dialog-footer"
className={cn(
"flex flex-col-reverse gap-2 group-data-[size=sm]/alert-dialog-content:grid group-data-[size=sm]/alert-dialog-content:grid-cols-2 sm:flex-row sm:justify-end",
className,
)}
{...props}
/>
);
}

function AlertDialogTitle({
className,
...props
}: React.ComponentProps<typeof AlertDialogPrimitive.Title>) {
return (
<AlertDialogPrimitive.Title
data-slot="alert-dialog-title"
className={cn(
"text-lg font-semibold sm:group-data-[size=default]/alert-dialog-content:group-has-data-[slot=alert-dialog-media]/alert-dialog-content:col-start-2",
className,
)}
{...props}
/>
);
}

function AlertDialogDescription({
className,
...props
}: React.ComponentProps<typeof AlertDialogPrimitive.Description>) {
return (
<AlertDialogPrimitive.Description
data-slot="alert-dialog-description"
className={cn("text-muted-foreground text-sm", className)}
{...props}
/>
);
}

function AlertDialogMedia({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="alert-dialog-media"
className={cn(
"bg-muted mb-2 inline-flex size-16 items-center justify-center rounded-md sm:group-data-[size=default]/alert-dialog-content:row-span-2 *:[svg:not([class*='size-'])]:size-8",
className,
)}
{...props}
/>
);
}

function AlertDialogAction({
className,
variant = "default",
size = "default",
...props
}: React.ComponentProps<typeof AlertDialogPrimitive.Action> &
Pick<React.ComponentProps<typeof Button>, "variant" | "size">) {
return (
<Button variant={variant} size={size} asChild>
<AlertDialogPrimitive.Action
data-slot="alert-dialog-action"
className={cn(className)}
{...props}
/>
</Button>
);
}

function AlertDialogCancel({
className,
variant = "outline",
size = "default",
...props
}: React.ComponentProps<typeof AlertDialogPrimitive.Cancel> &
Pick<React.ComponentProps<typeof Button>, "variant" | "size">) {
return (
<Button variant={variant} size={size} asChild>
<AlertDialogPrimitive.Cancel
data-slot="alert-dialog-cancel"
className={cn(className)}
{...props}
/>
</Button>
);
}

export {
AlertDialog,
AlertDialogAction,
AlertDialogCancel,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogMedia,
AlertDialogOverlay,
AlertDialogPortal,
AlertDialogTitle,
AlertDialogTrigger,
};
Loading