{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "suggested-actions",
  "title": "SuggestedActions",
  "description": "Render safe follow-up prompts from a validated AI tool payload.",
  "dependencies": [
    "ai",
    "zod"
  ],
  "registryDependencies": [
    "card",
    "button",
    "badge",
    "shobky/fable-ui/core"
  ],
  "files": [
    {
      "path": "components/fable-ui/suggested-actions/suggested-actions.tsx",
      "content": "\"use client\"\n\nimport { Badge } from \"@/components/ui/badge\"\nimport { Button } from \"@/components/ui/button\"\nimport { Card, CardContent, CardDescription, CardHeader, CardTitle } from \"@/components/ui/card\"\n\nexport type SuggestedAction = {\n  label: string\n  prompt: string\n  description?: string\n}\n\nexport type SuggestedActionsProps = {\n  title: string\n  description?: string\n  actions: SuggestedAction[]\n  isLoading?: boolean\n  isDisabled?: boolean\n  error?: {\n    title: string\n    description?: string\n  }\n  onAction?: (action: SuggestedAction) => void\n}\n\nexport function SuggestedActions({\n  title,\n  description,\n  actions,\n  isLoading,\n  isDisabled,\n  error,\n  onAction,\n}: SuggestedActionsProps) {\n  const areActionsDisabled = isDisabled || !onAction\n\n  return (\n    <Card className=\"w-full max-w-2xl\" data-fable-ui=\"suggested-actions\" aria-busy={isLoading || undefined}>\n      <CardHeader>\n        <div className=\"flex items-start justify-between gap-3\">\n          <div className=\"flex flex-col gap-1\">\n            <CardTitle className=\"text-base\">{title || \"Suggested actions\"}</CardTitle>\n            {description ? <CardDescription>{description}</CardDescription> : null}\n          </div>\n          <Badge variant=\"secondary\">safe prompts</Badge>\n        </div>\n      </CardHeader>\n      <CardContent className=\"flex flex-col gap-3\">\n        {isLoading ? (\n          <p className=\"text-sm text-muted-foreground\">Preparing suggestions...</p>\n        ) : error ? (\n          <div className=\"rounded-md border border-destructive/20 bg-destructive/5 p-3\">\n            <p className=\"text-sm font-medium text-destructive\">{error.title}</p>\n            {error.description ? <p className=\"text-sm text-muted-foreground\">{error.description}</p> : null}\n          </div>\n        ) : actions.length === 0 ? (\n          <p className=\"text-sm text-muted-foreground\">No safe follow-up actions are available.</p>\n        ) : (\n          actions.map((action) => (\n            <Button\n              key={`${action.label}-${action.prompt}`}\n              type=\"button\"\n              variant=\"outline\"\n              className=\"h-auto justify-start whitespace-normal px-3 py-2 text-left \"\n              disabled={areActionsDisabled}\n              onClick={() => onAction?.(action)}\n            >\n              <span className=\"flex flex-col gap-1\">\n                <span>{action.label}</span>\n                {action.description ? (\n                  <span className=\"text-xs font-normal text-muted-foreground\">{action.description}</span>\n                ) : null}\n              </span>\n            </Button>\n          ))\n        )}\n      </CardContent>\n    </Card>\n  )\n}\n",
      "type": "registry:component",
      "target": "@components/fable-ui/suggested-actions/suggested-actions.tsx"
    },
    {
      "path": "components/fable-ui/suggested-actions/index.ts",
      "content": "export * from \"./suggested-actions\"\n",
      "type": "registry:component",
      "target": "@components/fable-ui/suggested-actions/index.ts"
    },
    {
      "path": "lib/fable-ui/tools/show-next-actions-tool.ts",
      "content": "import { tool } from \"ai\"\nimport { z } from \"zod\"\n\nimport { defineFableComponent } from \"@/lib/fable-ui/core/definitions\"\nimport { SuggestedActions } from \"@/components/fable-ui/suggested-actions/suggested-actions\"\n\nexport const showNextActionsInputSchema = z.object({\n  title: z.string().min(1).default(\"Suggested actions\"),\n  description: z.string().min(1).optional(),\n  actions: z\n    .array(\n      z.object({\n        label: z.string().min(1),\n        prompt: z.string().min(1),\n        description: z.string().min(1).optional(),\n      }),\n    )\n    .min(1)\n    .max(6),\n})\n\nexport type ShowNextActionsInput = z.infer<typeof showNextActionsInputSchema>\n\nexport function createShowNextActionsTool() {\n  return tool({\n    description:\n      \"Show safe follow-up prompts the user can send next. The actions must not call host APIs directly.\",\n    inputSchema: showNextActionsInputSchema,\n    execute: async (input) => input,\n  })\n}\n\nexport const showNextActions = defineFableComponent({\n  name: \"show_next_actions\",\n  schema: showNextActionsInputSchema,\n  tool: createShowNextActionsTool(),\n  renderer: {\n    Component: SuggestedActions,\n    loadingProps: { title: \"Suggested actions\", actions: [], isLoading: true },\n    emptyProps: { title: \"Suggested actions\", actions: [] },\n    errorProps: (description: string) => ({\n      title: \"Suggested actions\",\n      actions: [],\n      error: { title: \"Suggestions unavailable\", description },\n    }),\n    toProps: (data: ShowNextActionsInput, handlers) => ({\n      ...data,\n      onAction: handlers.onSuggestedAction,\n    }),\n  },\n})\n",
      "type": "registry:lib",
      "target": "@lib/fable-ui/tools/show-next-actions-tool.ts"
    },
    {
      "path": "lib/fable-ui/manifests/show-next-actions.md",
      "content": "---\ntool: show_next_actions\ntype: registry:component\n---\n\n# show_next_actions\n\nUse `show_next_actions` for safe follow-up prompts the user may choose to send back into the chat.\n\nEach action has UI copy and model-facing intent:\n\n- `label` is the short button text shown to the user.\n- `prompt` is the complete user message the host chat sends if the user clicks the button.\n- `description` may add brief context under the label.\n\nPrompts must be complete enough to send as the user's next turn without hidden state. Good prompts include the subject and desired operation, such as \"Compare this revenue metric to yesterday\" or \"Show the source rows for this answer.\"\n\nDo not use this tool to perform host API calls, writes, purchases, deletes, sends, refunds, approvals, or status changes. Suggested actions are prompt-only. Side effects belong in confirmation, form, or host-owned action flows where the app validates and executes the operation.\n",
      "type": "registry:file",
      "target": "@lib/fable-ui/manifests/show-next-actions.md"
    }
  ],
  "type": "registry:component"
}