Thinking

Bir modelin çalışırken ne yaptığını gösterin. Bir shader küresi ve her adımı izleyen canlı bir etiket, aramaların, kaynak çiplerinin ve akıl yürütmenin daraltılabilir bir izi, ardından desteklediği iddiaların hemen yanında alıntılar içeren bir yanıt.

Uzun beklemeler, işin yapıldığını görebildiğinizde daha kısa hissedilir. Thinking, bir yanıtın en üstüne canlı bir durum satırı koyar: küçük bir shader küresi, “Searching the web” gibi sade sözcüklerle geçerli adım ve çalışan bir zamanlayıcı. Aramaların, kaynakların ve akıl yürütmenin tüm izini okumak için açın.

Kalın bir başlık ve ardından bir paragraf olarak yazılan akıl yürütme bölümlere ayrılır ve yarım yazılmış başlıklar kapanana kadar tutulur. Araç adımları çalışırken bir spinner ve şimdiki zaman etiketi gösterir, ardından ne yaptıklarına geçer; altında kaynak çipleri vardır.

İz, model çalışırken açılır ve bittiğinde, biri kendisi açıp kapatmadıysa, “Thought for 12s” olarak daralır. Yanıt ardından kaynaklarını satır içinde alıntılar: CitedText, [1] ve [2][3] ifadelerini hover'da başlık, alan adı ve alıntı parçası gösteren kompakt çiplere çevirir.

  1. Pro registry'yi components.json dosyasına ekleyin

    components.json
    {
      "registries": {
        "@hextaui-pro": {
          "url": "https://hextaui.com/r/pro/{name}.json",
          "headers": {
            "Authorization": "Bearer ${HEXTAUI_PRO_TOKEN}"
          }
        }
      }
    }
  2. Token'ınızı ekleyin

    Hesap sayfanızda bir token oluşturun ve .env.local dosyasına HEXTAUI_PRO_TOKEN olarak ekleyin.

  3. Bloğu ekleyin

    pnpm dlx shadcn@latest add @hextaui-pro/thinking

AI SDK ile

Bir useChat mesajının parçalarını eşleyin: reasoning parçaları Reasoning'e, metin CitedText'e, source-url parçaları kaynakları olarak. Modelden, desteklediği cümlenin sonunda [1], [2] ile alıntı yapmasını isteyin.

"use client"

import { useChat } from "@ai-sdk/react"
import type { UIMessage } from "ai"

import { CitedText } from "@/components/blocks/thinking/cited-text"
import { Reasoning } from "@/components/blocks/thinking/reasoning"
import type { Source } from "@/components/blocks/thinking/sources"

function AssistantMessage({ message }: { message: UIMessage }) {
  const sources: Source[] = message.parts.flatMap((part) =>
    part.type === "source-url"
      ? [{ id: part.sourceId, url: part.url, title: part.title ?? part.url }]
      : []
  )

  return (
    <div className="flex flex-col gap-4">
      {message.parts.map((part, index) => {
        if (part.type === "reasoning") {
          return (
            <Reasoning
              key={index}
              text={part.text}
              streaming={part.state === "streaming"}
            />
          )
        }
        if (part.type === "text") {
          return (
            <CitedText
              key={index}
              text={part.text}
              sources={sources}
              streaming={part.state === "streaming"}
            />
          )
        }
        return null
      })}
    </div>
  )
}

export function Chat() {
  const { messages } = useChat()

  return messages.map((message) =>
    message.role === "assistant" ? (
      <AssistantMessage key={message.id} message={message} />
    ) : null
  )
}

Araç adımlarıyla

Araç çağrılarını adımlara çevirin. Hâlâ çalışan bir çağrı spinner ve shimmer gösterir, çıktısı geldiğinde işaretlenir.

"use client"

import { getToolName, isToolUIPart, type UIMessage } from "ai"

import { Reasoning, type ReasoningStep } from "@/components/blocks/thinking/reasoning"

const labels: Record<string, Pick<ReasoningStep, "label" | "kind">> = {
  webSearch: { label: "Searching the web", kind: "search" },
  readPage: { label: "Reading sources", kind: "read" },
  runCode: { label: "Running code", kind: "code" },
}

export function Thoughts({
  message,
  streaming,
}: {
  message: UIMessage
  streaming: boolean
}) {
  const steps: ReasoningStep[] = message.parts
    .filter(isToolUIPart)
    .map((part) => {
      const name = getToolName(part)
      return {
        id: part.toolCallId,
        ...(labels[name] ?? { label: name, kind: "think" }),
        status: part.state.startsWith("output") ? "done" : "active",
      }
    })

  const text = message.parts
    .flatMap((part) => (part.type === "reasoning" ? [part.text] : []))
    .join("\n\n")

  return <Reasoning steps={steps} text={text} streaming={streaming} />
}

Yapı

Dıştan içe doğru birleştirdiğiniz parçalar.

ParçaAçıklama
ReasoningDaraltılabilir durum satırı ve iz. Akıl yürütme metnini, adımları ya da ikisini alır.
ThinkingOrbAnimasyonlu shader küresi. Kompakt bir meşgul göstergesi olarak tek başına kullanın.
CitedTextYanıt, [n] işaretleri alıntı çiplerine dönüştürülmüş olarak.
CitationKaynaklarını listeleyen bir hover kartlı tek çip.
SourceChipsBir adımın altında kullanılan kaynak çipleri satırı.

Reasoning

Ayrıca children dışındaki her div prop'unu kabul eder.

PropTürVarsayılan
textŞimdiye kadarki akıl yürütme. **Kalın** satırlar bölüm başlıkları olur.
string""
streamingModelin hâlâ çalışıp çalışmadığı. Küreyi, shimmer'ı ve zamanlayıcıyı yönlendirir.
booleanfalse
stepsAkıl yürütmenin üstünde gösterilen araç adımları.
ReasoningStep[][]
durationBittiğinde gösterilecek saniye. Ölçülen süreyi kullanmak için atlayın.
number–
labelAkarken canlı etiketi geçersiz kılar.
string–
defaultOpenBaşlangıç açık durumu. Varsayılan olarak akarken açıktır.
boolean–
autoCollapseBiri değiştirmediyse akış bitince daraltır.
booleantrue

ReasoningStep

steps içindeki bir girdi.

PropTürVarsayılan
idKararlı anahtar.
string–
labelNe yaptığı, örneğin “Searching for debounce”.
string–
doneLabelNe yaptığı, status done olunca gösterilir.
string–
statusEtkin adımlar bir spinner gösterir ve canlı etiketi yönlendirir.
"active" | "done"–
kindSimgeyi ve aşama metnini seçer.
"search" | "read" | "think" | "code""think"
phaseİz açıkken özel aşama metni.
string–
detailAdımın altında ek içerik.
ReactNode–
sourcesAdımın altında gösterilen çipler.
Source[]–

CitedText

Ayrıca children dışındaki her div prop'unu kabul eder.

PropTürVarsayılan
textYanıt, iddialardan sonra [1] tarzı işaretlerle.
string–
sourcesAlıntı sırasıyla kaynaklar, yani [1] sources[0]'dır.
Source[]–
streamingİmleci gösterir ve metni hızlandırır.
booleanfalse
smoothHızlandırmayı kapatır.
booleantrue
PropTürVarsayılan
idKararlı anahtar.
string–
urlYeni sekmede açılır.
string–
titleHover kartında gösterilir.
string–
nameÇip için kısa site adı. Varsayılan olarak alan adıdır.
string–
snippetBaşlığın altında gösterilen alıntı.
string–
iconFavicon URL'si. Yoksa ilk harfe düşer.
string–

ThinkingOrb

Ayrıca her span prop'unu kabul eder.

PropTürVarsayılan
activetrue iken canlanır, false iken durur.
boolean–
colorsShader için üç hex rengi.
{ deep, mid, light }blue
speedAnimasyon hızı çarpanı.
number–
TuşAction
TabDurum satırına, ardından ize, ardından her alıntıya geçer. Odaktaki bir alıntı hover kartını açar.
EnterSpaceİzi açar veya kapatır.
EscAçık bir alıntı kartını kapatır.
  • Durum satırı, özetini polite bir live region ile duyuran bir düğmedir; böylece ekran okuyucu kullanıcıları zamanlayıcının her tikini duymadan “Searching the web”, ardından “Thought for 12s” duyar.
  • Her alıntı çipi “Source: MDN: Debounce” etiketli gerçek bir bağlantıdır; böylece bir sayı olarak değil bir kaynak olarak okunur.
  • Azaltılmış harekette küre durağan bir kare render eder, shimmer durur ve satırlar kaymadan belirir.

Şunlarla geliştirildi

Thinking bloğunun yapıldığı ücretsiz HextaUI bileşenleri. Her biri tek başına yüklenir.

Kod

5 dosya, components/blocks/thinking konumuna eklendi.