{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "agent-advisor",
  "title": "Agent advisor",
  "description": "Ask the Poker Study AI agent what it would do at a table snapshot, and see which model answered. Needs your API key.",
  "registryDependencies": [
    "https://www.pokerstudy.ai/r/poker-core.json",
    "https://www.pokerstudy.ai/r/playing-card.json",
    "https://www.pokerstudy.ai/r/pokerstudy-api.json"
  ],
  "files": [
    {
      "path": "src/components/pokerstudy/agent-advisor.tsx",
      "content": "\"use client\";\n\nimport { useState } from \"react\";\nimport { Board, HoleCards } from \"@/components/pokerstudy/playing-card\";\nimport { actionColor, type DecideResponse, type TableSnapshot } from \"@/lib/pokerstudy/poker\";\n\n/** `source` is the agent's own tag; \"ranges\" means the solver's preflop ranges answered. */\nconst SOURCE_LABEL: Record<string, string> = { ranges: \"solver preflop ranges\" };\n\ntype State =\n  | { status: \"idle\" }\n  | { status: \"loading\" }\n  | { status: \"error\"; message: string }\n  | { status: \"done\"; result: DecideResponse };\n\nfunction kindOf(action: string) {\n  return action === \"fold\" ? \"fold\" : action === \"check\" ? \"check\" : action === \"call\" ? \"call\" : \"raise\";\n}\n\n/**\n * Ask the Poker Study AI agent what it would do at a table snapshot. Shows\n * the hand and board, and after \"Ask the agent\" the action, the amount, and\n * which model answered: solver ranges preflop, heuristics after the flop.\n *\n * `endpoint` defaults to the `/api/pokerstudy/decide` route, which adds your\n * key on the server.\n */\nexport function AgentAdvisor({\n  snapshot,\n  endpoint = \"/api/pokerstudy/decide\",\n  initialResult,\n}: {\n  snapshot: TableSnapshot;\n  endpoint?: string;\n  /** Render a result without calling the API, e.g. for a static preview. */\n  initialResult?: DecideResponse;\n}) {\n  const [state, setState] = useState<State>(initialResult ? { status: \"done\", result: initialResult } : { status: \"idle\" });\n  const bigBlind = snapshot.big_blind ?? 20;\n\n  async function ask() {\n    setState({ status: \"loading\" });\n    try {\n      const res = await fetch(endpoint, {\n        method: \"POST\",\n        headers: { \"content-type\": \"application/json\" },\n        body: JSON.stringify(snapshot),\n      });\n      const body = (await res.json().catch(() => null)) as (DecideResponse & { error?: string }) | null;\n      if (!res.ok || !body || body.error) setState({ status: \"error\", message: body?.error ?? `HTTP ${res.status}` });\n      else setState({ status: \"done\", result: body });\n    } catch (err) {\n      setState({ status: \"error\", message: (err as Error).message });\n    }\n  }\n\n  const result = state.status === \"done\" ? state.result : null;\n  return (\n    <div className=\"flex w-full max-w-[560px] flex-col gap-5\">\n      <div className=\"flex flex-wrap items-end gap-6\">\n        <div className=\"flex flex-col gap-1.5\">\n          <span className=\"text-xs text-muted-foreground\">Hand</span>\n          <HoleCards cards={snapshot.hole} size=\"md\" />\n        </div>\n        {snapshot.board && snapshot.board.length > 0 ? (\n          <div className=\"flex flex-col gap-1.5\">\n            <span className=\"text-xs text-muted-foreground\">Board</span>\n            <Board cards={snapshot.board} size=\"sm\" />\n          </div>\n        ) : null}\n        <div className=\"flex flex-col gap-1.5 text-sm\">\n          <span className=\"text-xs text-muted-foreground\">Pot</span>\n          <span className=\"font-mono tabular-nums text-foreground\">\n            {snapshot.pot ?? bigBlind * 1.5} <span className=\"text-muted-foreground\">· BB {bigBlind}</span>\n          </span>\n        </div>\n      </div>\n\n      <div aria-live=\"polite\" className=\"flex min-h-[4.5rem] flex-col items-start gap-2\">\n        {result ? (\n          <>\n            <span\n              className=\"rounded-md border-2 px-3 py-1.5 font-mono text-sm font-semibold uppercase text-foreground\"\n              style={{ borderColor: actionColor(kindOf(result.action)) }}\n            >\n              {result.action}\n              {result.amount ? ` ${result.amount}` : \"\"}\n            </span>\n            {result.source ? (\n              <span className=\"text-xs text-muted-foreground\">\n                From {SOURCE_LABEL[result.source] ?? result.source}\n              </span>\n            ) : null}\n          </>\n        ) : state.status === \"error\" ? (\n          <p role=\"alert\" className=\"text-sm text-red-300\">\n            {state.message}\n          </p>\n        ) : null}\n        <button\n          type=\"button\"\n          onClick={ask}\n          disabled={state.status === \"loading\"}\n          className=\"rounded-md bg-foreground px-3 py-1.5 text-sm font-semibold text-background disabled:opacity-50\"\n        >\n          {state.status === \"loading\" ? \"Thinking…\" : result ? \"Ask again\" : \"Ask the agent\"}\n        </button>\n      </div>\n    </div>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/pokerstudy/agent-advisor.tsx"
    }
  ],
  "type": "registry:block"
}