{"$schema":"https://ui.shadcn.com/schema/registry-item.json","name":"model-preferences","type":"registry:block","title":"Model & Memory Preferences","description":"A preferences screen that picks the model, reasoning level and tools, and manages persistent memory.","author":"Scrim UI (https://scrimui.dev)","categories":["pattern"],"docs":"https://scrimui.dev/patterns/model-preferences","dependencies":[],"registryDependencies":["https://scrimui.dev/r/model-selector.json","https://scrimui.dev/r/reasoning-level.json","https://scrimui.dev/r/tool-toggle.json","https://scrimui.dev/r/memory-list.json"],"files":[{"path":"src/showcase/patterns/model-preferences/model-preferences.tsx","content":"\"use client\";\n\nimport * as React from \"react\";\nimport { ModelSelector, type ModelOption } from \"@/components/ui/model-selector\";\nimport {\n  ReasoningLevel,\n  type ReasoningLevel as ReasoningLevelValue,\n} from \"@/components/ui/reasoning-level\";\nimport { ToolToggle, type ToolSetting } from \"@/components/ui/tool-toggle\";\nimport { MemoryList, type MemoryItem } from \"@/components/ui/memory-list\";\n\n/* ------------------------------------------------------------------ */\n/* Data                                                                */\n/* ------------------------------------------------------------------ */\n\nconst MODELS: ModelOption[] = [\n  { id: \"sonnet\", name: \"Claude Sonnet 5\", hint: \"Balanced speed and quality\", badges: [\"Default\"], icon: <ClaudeMark /> },\n  { id: \"opus\", name: \"Claude Opus 5\", hint: \"Best for hard problems\", badges: [\"Deep thinking\"], icon: <ClaudeMark /> },\n  { id: \"haiku\", name: \"Claude Haiku 4.5\", hint: \"Fastest responses\", badges: [\"Fast\"], icon: <ClaudeMark /> },\n];\n\nfunction initTools(): ToolSetting[] {\n  return [\n    {\n      id: \"search\",\n      name: \"Web search\",\n      description: \"Find current information online\",\n      enabled: true,\n      icon: <SearchIcon />,\n    },\n    {\n      id: \"code\",\n      name: \"Code execution\",\n      description: \"Run code to verify answers\",\n      enabled: true,\n      icon: <CodeIcon />,\n    },\n    {\n      id: \"files\",\n      name: \"File access\",\n      description: \"Read and edit attached files\",\n      enabled: false,\n      icon: <FileIcon />,\n    },\n    {\n      id: \"browser\",\n      name: \"Browser\",\n      description: \"Open pages from the conversation\",\n      enabled: false,\n      icon: <GlobeIcon />,\n    },\n  ];\n}\n\nconst INITIAL_MEMORIES: MemoryItem[] = [\n  {\n    id: \"m1\",\n    text: \"Builds AI chat interfaces in TypeScript with Tailwind and zero UI dependencies.\",\n    updatedAt: \"2d ago\",\n  },\n  { id: \"m2\", text: \"Prefers zinc-based palettes and compact, dependency-free components.\", updatedAt: \"5d ago\" },\n  { id: \"m3\", text: \"Shipping a voice assistant pattern this week.\", updatedAt: \"Today\" },\n];\n\n/* ------------------------------------------------------------------ */\n/* Icons                                                               */\n/* ------------------------------------------------------------------ */\n\n/**\n * The provider's mark, inlined so this pattern stays dependency-free. Swap it\n * for whichever providers your own model list uses.\n */\nfunction ClaudeMark() {\n  return (\n    <svg viewBox=\"0 0 24 24\" width=\"13\" height=\"13\" aria-hidden className=\"shrink-0 fill-[#d97757]\">\n      <path d=\"M17.3041 3.541h-3.6718l6.696 16.918H24Zm-10.6082 0L0 20.459h3.7442l1.3693-3.5527h7.0052l1.3693 3.5528h3.7442L10.5363 3.5409Zm-.3712 10.2232 2.2914-5.9456 2.2914 5.9456Z\" />\n    </svg>\n  );\n}\n\nfunction SearchIcon() {\n  return (\n    <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" width=\"15\" height=\"15\">\n      <circle cx=\"11\" cy=\"11\" r=\"7\" />\n      <path d=\"m21 21-4.3-4.3\" />\n    </svg>\n  );\n}\n\nfunction CodeIcon() {\n  return (\n    <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" width=\"15\" height=\"15\">\n      <path d=\"m8 7-5 5 5 5\" />\n      <path d=\"m16 7 5 5-5 5\" />\n    </svg>\n  );\n}\n\nfunction FileIcon() {\n  return (\n    <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" width=\"15\" height=\"15\">\n      <path d=\"M14.5 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7.5L14.5 2Z\" />\n      <path d=\"M14 2v6h6\" />\n    </svg>\n  );\n}\n\nfunction GlobeIcon() {\n  return (\n    <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" width=\"15\" height=\"15\">\n      <circle cx=\"12\" cy=\"12\" r=\"10\" />\n      <path d=\"M2 12h20M12 2a15.3 15.3 0 0 1 0 20 15.3 15.3 0 0 1 0-20Z\" />\n    </svg>\n  );\n}\n\n/* ------------------------------------------------------------------ */\n/* ModelPreferencesPattern                                             */\n/* ------------------------------------------------------------------ */\n\nexport function ModelPreferencesPattern() {\n  const [model, setModel] = React.useState(\"sonnet\");\n  const [level, setLevel] = React.useState<ReasoningLevelValue>(\"balanced\");\n  const [tools, setTools] = React.useState<ToolSetting[]>(initTools);\n  const [memories, setMemories] = React.useState<MemoryItem[]>(INITIAL_MEMORIES);\n  const idRef = React.useRef(4);\n\n  function toggleTool(id: string, enabled: boolean) {\n    setTools((ts) => ts.map((t) => (t.id === id ? { ...t, enabled } : t)));\n  }\n\n  function addMemory(text: string) {\n    setMemories((m) => [...m, { id: `m${idRef.current++}`, text, updatedAt: \"Just now\" }]);\n  }\n\n  function forgetMemory(id: string) {\n    setMemories((m) => m.filter((item) => item.id !== id));\n  }\n\n  return (\n    <div className=\"flex h-[560px] flex-col overflow-hidden rounded-2xl border border-zinc-200 bg-white dark:border-zinc-800 dark:bg-zinc-900\">\n      {/* Header */}\n      <div className=\"flex items-center justify-between border-b border-zinc-200 px-5 py-3.5 dark:border-zinc-800\">\n        <div>\n          <p className=\"text-sm font-semibold text-zinc-900 dark:text-zinc-100\">\n            Model &amp; Memory Preferences\n          </p>\n          <p className=\"mt-0.5 text-xs text-zinc-500 dark:text-zinc-400\">\n            How the assistant thinks, which tools it may use, and what it remembers.\n          </p>\n        </div>\n        <span className=\"inline-flex items-center gap-1.5 rounded-full bg-emerald-100 px-2 py-0.5 text-[11px] font-medium text-emerald-700 dark:bg-emerald-900/40 dark:text-emerald-400\">\n          <span className=\"h-1.5 w-1.5 rounded-full bg-current\" />\n          Saved\n        </span>\n      </div>\n\n      <div className=\"flex min-h-0 flex-1\">\n        {/* Settings */}\n        <div className=\"flex-1 space-y-6 overflow-y-auto p-5\">\n          <section className=\"space-y-2\">\n            <div>\n              <p className=\"text-sm font-medium text-zinc-900 dark:text-zinc-100\">Default model</p>\n              <p className=\"mt-0.5 text-xs text-zinc-500 dark:text-zinc-400\">\n                Used for new conversations; you can still switch per message.\n              </p>\n            </div>\n            <ModelSelector options={MODELS} value={model} onSelect={setModel} />\n          </section>\n\n          <ReasoningLevel value={level} onChange={setLevel} />\n\n          <ToolToggle\n            tools={tools}\n            onToggle={toggleTool}\n            title=\"Allowed tools\"\n            description=\"What the assistant may do on your behalf\"\n          />\n        </div>\n\n        {/* Memory */}\n        <div className=\"hidden w-80 shrink-0 flex-col overflow-y-auto border-l border-zinc-200 p-5 dark:border-zinc-800 md:flex\">\n          <MemoryList\n            items={memories}\n            onAdd={addMemory}\n            onForget={forgetMemory}\n            description=\"Facts the assistant keeps across conversations\"\n          />\n          <p className=\"mt-3 text-[11px] leading-5 text-zinc-500 dark:text-zinc-400\">\n            Memories are included with each message so the assistant stays consistent. Remove\n            anything you do not want stored.\n          </p>\n        </div>\n      </div>\n    </div>\n  );\n}\n","type":"registry:block","target":"components/blocks/model-preferences.tsx"}]}