63 lines
1.8 KiB
Plaintext
63 lines
1.8 KiB
Plaintext
---
|
|
title: August 2026 - Human in the Loop
|
|
description: Mock paused tool calls, approvals, and continuations for the AI SDK with @shadcn/helpers.
|
|
date: 2026-08-12
|
|
---
|
|
|
|
**@shadcn/helpers** can now mock human-in-the-loop flows for the AI SDK. A
|
|
scripted conversation can pause for real user input, wait for an approval, and
|
|
continue with whatever the user decided.
|
|
|
|
Everything streams through the real
|
|
`useChat` lifecycle, so your tool cards, approval prompts, and question flows
|
|
behave exactly as they would in production.
|
|
|
|
```ts showLineNumbers
|
|
import { createChat } from "@shadcn/helpers/ai-sdk"
|
|
|
|
const chat = createChat<ChatMessage>()
|
|
.user("Help me plan the next prototype.")
|
|
.assistant(({ writer }) => {
|
|
writer.text("A couple of questions before I start.")
|
|
writer.tool("askQuestions", { input: { questions } })
|
|
})
|
|
.assistant(({ writer, toolCall }) => {
|
|
writer.text(
|
|
toolCall?.name === "askQuestions" && toolCall.output
|
|
? `Starting with ${toolCall.output.answers.direction}.`
|
|
: "Starting now."
|
|
)
|
|
})
|
|
```
|
|
|
|
Pass `needsApproval` to pause behind the user's decision. The scripted output
|
|
streams after approval, and denial streams automatically.
|
|
|
|
```ts showLineNumbers
|
|
chat
|
|
.assistant(({ writer }) => {
|
|
writer.text("That will archive 3 drafts. I need your approval.")
|
|
writer.tool("archiveDrafts", {
|
|
input: { count: 3 },
|
|
needsApproval: true,
|
|
output: { archived: 3 },
|
|
})
|
|
})
|
|
.assistant(({ writer, toolCall }) => {
|
|
writer.text(
|
|
toolCall?.approved ? "Archived 3 drafts." : "Okay, leaving them in place."
|
|
)
|
|
})
|
|
```
|
|
|
|
<div className="flex flex-wrap gap-2">
|
|
<Button asChild size="sm">
|
|
<Link
|
|
href="/docs/helpers/ai-sdk#human-in-the-loop"
|
|
className="mt-6 no-underline!"
|
|
>
|
|
Read the Docs
|
|
</Link>
|
|
</Button>
|
|
</div>
|