思维链
一个可折叠组件,可视化 AI 推理步骤,支持搜索结果、图片和逐步进度指示器。
ChainOfThought 组件提供了 AI 推理过程的可视化表示,显示逐步思考,支持搜索结果、图片和进度指示器。它帮助用户理解 AI 如何得出结论。
Install using CLI
AI Elements Vue
shadcn-vue CLI
npx ai-elements-vue@latest add chain-of-thought
npx shadcn-vue@latest add https://registry.ai-elements-vue.com/chain-of-thought.json
Install Manually
Copy and paste the following files into the same folder.
ChainOfThought.vue
ChainOfThoughtHeader.vue
ChainOfThoughtStep.vue
ChainOfThoughtSearchResults.vue
ChainOfThoughtSearchResult.vue
ChainOfThoughtContent.vue
ChainOfThoughtImage.vue
context.ts
index.ts
<script setup lang="ts">
import type { HTMLAttributes, Ref } from 'vue'
import { cn } from '@repo/shadcn-vue/lib/utils'
import { useVModel } from '@vueuse/core'
import { provide } from 'vue'
import { ChainOfThoughtContextKey } from './context'
interface ChainOfThoughtProps {
modelValue?: boolean
defaultOpen?: boolean
class?: HTMLAttributes['class']
}
const props = withDefaults(
defineProps<ChainOfThoughtProps>(),
{
defaultOpen: false,
modelValue: undefined,
},
)
const emit = defineEmits<{
(e: 'update:modelValue', value: boolean): void
}>()
const isOpen = useVModel(props, 'modelValue', emit, {
defaultValue: props.defaultOpen,
passive: true,
})
provide(ChainOfThoughtContextKey, isOpen as Ref<boolean>)
</script>
<template>
<div
:class="cn('not-prose max-w-prose space-y-4', props.class)"
v-bind="$attrs"
>
<slot />
</div>
</template>
<script setup lang="ts">
import type { HtmlHTMLAttributes } from 'vue'
import {
Collapsible,
CollapsibleTrigger,
} from '@repo/shadcn-vue/components/ui/collapsible'
import { cn } from '@repo/shadcn-vue/lib/utils'
import { BrainIcon, ChevronDownIcon } from 'lucide-vue-next'
import { useChainOfThought } from './context'
const props = defineProps<{
class?: HtmlHTMLAttributes['class']
}>()
const { isOpen, setIsOpen } = useChainOfThought()
</script>
<template>
<Collapsible :open="isOpen" @update:open="setIsOpen">
<CollapsibleTrigger
:class="
cn(
'flex w-full items-center gap-2 text-muted-foreground text-sm transition-colors hover:text-foreground',
props.class,
)
"
v-bind="$attrs"
>
<BrainIcon class="size-4" />
<span class="flex-1 text-left">
<slot>Chain of Thought</slot>
</span>
<ChevronDownIcon
:class="
cn(
'size-4 transition-transform',
isOpen ? 'rotate-180' : 'rotate-0',
)
"
/>
</CollapsibleTrigger>
</Collapsible>
</template>
<script setup lang="ts">
import type { HTMLAttributes } from 'vue'
import { cn } from '@repo/shadcn-vue/lib/utils'
const props = withDefaults(
defineProps<{
label: string
description?: string
status?: 'complete' | 'active' | 'pending'
class?: HTMLAttributes['class']
}>(),
{
status: 'complete',
description: undefined,
},
)
const statusStyles = {
complete: 'text-muted-foreground',
active: 'text-foreground',
pending: 'text-muted-foreground/50',
}
</script>
<template>
<div
:class="
cn(
'flex gap-2 text-sm',
statusStyles[props.status],
'fade-in-0 slide-in-from-top-2 animate-in',
props.class,
)
"
v-bind="$attrs"
>
<div class="relative mt-0.5">
<slot name="icon" />
<div
class="-mx-px absolute top-7 bottom-0 left-1/2 w-px bg-border"
/>
</div>
<div class="flex-1 space-y-2">
<div>{{ props.label }}</div>
<div
v-if="props.description"
class="text-muted-foreground text-xs"
>
{{ props.description }}
</div>
<slot />
</div>
</div>
</template>
<script setup lang="ts">
import type { HtmlHTMLAttributes } from 'vue'
import { cn } from '@repo/shadcn-vue/lib/utils'
const props = defineProps<{
class?: HtmlHTMLAttributes['class']
}>()
</script>
<template>
<div
:class="cn('flex items-center gap-2', props.class)"
v-bind="$attrs"
>
<slot />
</div>
</template>
<script setup lang="ts">
import type { HTMLAttributes } from 'vue'
import { Badge } from '@repo/shadcn-vue/components/ui/badge'
import { cn } from '@repo/shadcn-vue/lib/utils'
const props = defineProps<{
class?: HTMLAttributes['class']
}>()
</script>
<template>
<Badge
:class="
cn(
'gap-1 px-2 py-0.5 font-normal text-xs',
props.class,
)
"
variant="secondary"
v-bind="$attrs"
>
<slot />
</Badge>
</template>
<script setup lang="ts">
import type { HTMLAttributes } from 'vue'
import {
Collapsible,
CollapsibleContent,
} from '@repo/shadcn-vue/components/ui/collapsible'
import { cn } from '@repo/shadcn-vue/lib/utils'
import { useChainOfThought } from './context'
const props = defineProps<{
class?: HTMLAttributes['class']
}>()
const { isOpen } = useChainOfThought()
</script>
<template>
<Collapsible :open="isOpen">
<CollapsibleContent
:class="
cn(
'mt-2 space-y-3',
'data-[state=closed]:fade-out-0 data-[state=closed]:slide-out-to-top-2 data-[state=open]:slide-in-from-top-2 text-popover-foreground outline-none data-[state=closed]:animate-out data-[state=open]:animate-in',
props.class,
)
"
v-bind="$attrs"
>
<slot />
</CollapsibleContent>
</Collapsible>
</template>
<script setup lang="ts">
import type { HTMLAttributes } from 'vue'
import { cn } from '@repo/shadcn-vue/lib/utils'
const props = defineProps<{
caption?: string
class?: HTMLAttributes['class']
}>()
</script>
<template>
<div
:class="cn('mt-2 space-y-2', props.class)"
v-bind="$attrs"
>
<div
class="relative flex max-h-[22rem] items-center justify-center overflow-hidden rounded-lg bg-muted p-3"
>
<slot />
</div>
<p v-if="caption" class="text-muted-foreground text-xs">
{{ props.caption }}
</p>
</div>
</template>
import type { InjectionKey, Ref } from 'vue'
import { inject } from 'vue'
export const ChainOfThoughtContextKey: InjectionKey<Ref<boolean>> = Symbol(
'ChainOfThoughtContext',
)
export function useChainOfThought() {
const isOpen = inject(ChainOfThoughtContextKey)
if (!isOpen) {
throw new Error(
'useChainOfThought must be used within a <ChainOfThought> component',
)
}
const setIsOpen = (open: boolean) => {
isOpen.value = open
}
return { isOpen, setIsOpen }
}
export { default as ChainOfThought } from './ChainOfThought.vue'
export { default as ChainOfThoughtContent } from './ChainOfThoughtContent.vue'
export { default as ChainOfThoughtHeader } from './ChainOfThoughtHeader.vue'
export { default as ChainOfThoughtImage } from './ChainOfThoughtImage.vue'
export { default as ChainOfThoughtSearchResult } from './ChainOfThoughtSearchResult.vue'
export { default as ChainOfThoughtSearchResults } from './ChainOfThoughtSearchResults.vue'
export { default as ChainOfThoughtStep } from './ChainOfThoughtStep.vue'
特性
- 可折叠界面,具有由 Reka UI 驱动的平滑动画
- AI 推理过程的逐步可视化
- 支持不同的步骤状态(完成、活动、待处理)
- 内置搜索结果显示,带有徽章样式
- 图片支持,带有视觉内容的标题
- 不同步骤类型的自定义图标
- 使用 Inject/Provide API 的上下文感知组件
- 完全使用 TypeScript 类型化
- 可访问,具有键盘导航支持
- 响应式设计,适应不同的屏幕尺寸
- 平滑的淡入淡出和滑动动画,用于内容过渡
- 可组合架构,用于灵活的自定义
Props
<ChainOfThought />
defaultOpenboolean
classstring
''<ChainOfThoughtHeader />
classstring
''<ChainOfThoughtStep />
labelstring
descriptionstring
status'complete' | 'active' | 'pending'
'complete'classstring
''<ChainOfThoughtSearchResults />
classstring
''<ChainOfThoughtSearchResult />
classstring
''<ChainOfThoughtContent />
classstring
''<ChainOfThoughtImage />
captionstring
classstring
''