Skip to content

Commit

Permalink
feat (ai/ui): set body and headers directly on options for handleSubm…
Browse files Browse the repository at this point in the history
…it and append (#2239)
  • Loading branch information
lgrammel authored Jul 11, 2024
1 parent 3236fa0 commit 56bbc2a
Show file tree
Hide file tree
Showing 10 changed files with 192 additions and 64 deletions.
10 changes: 10 additions & 0 deletions .changeset/metal-mirrors-stare.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
'@ai-sdk/ui-utils': patch
'@ai-sdk/svelte': patch
'@ai-sdk/react': patch
'@ai-sdk/solid': patch
'ai': patch
'@ai-sdk/vue': patch
---

feat (ai/ui): set body and headers directly on options for handleSubmit and append
10 changes: 4 additions & 6 deletions content/docs/05-ai-sdk-ui/02-chatbot.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -224,10 +224,10 @@ In this example, the `useChat` hook sends a POST request to the `/api/custom-cha

## Setting custom body fields per request

You can configure custom `body` fields on a per-request basis using the `options` field of the `handleSubmit` function.
You can configure custom `body` fields on a per-request basis using the `body` option of the `handleSubmit` function.
This is useful if you want to pass in additional information to your backend that is not part of the message list.

```tsx filename="app/page.tsx" highlight="19-21"
```tsx filename="app/page.tsx" highlight="18-20"
'use client';

import { useChat } from 'ai/react';
Expand All @@ -245,10 +245,8 @@ export default function Chat() {
<form
onSubmit={event => {
handleSubmit(event, {
options: {
body: {
customKey: 'customValue',
},
body: {
customKey: 'customValue',
},
});
}}
Expand Down
62 changes: 37 additions & 25 deletions content/docs/07-reference/ai-sdk-ui/01-use-chat.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -160,9 +160,33 @@ Allows you to easily create a conversational user interface for your chatbot app
},
{
name: 'append',
type: '(message: Message | CreateMessage, chatRequestOptions: { options: { headers, body } }) => Promise<string | undefined>',
type: '(message: Message | CreateMessage, options?: ChatRequestOptions) => Promise<string | undefined>',
description:
'Function to append a message to the chat, triggering an API call for the AI response. It returns a promise that resolves to full response message content when the API call is successfully finished, or throws an error when the API call fails.',
properties: [
{
type: 'ChatRequestOptions',
parameters: [
{
name: 'headers',
type: 'Record<string, string> | Headers',
description:
'Additional headers that should be to be passed to the API endpoint.',
},
{
name: 'body',
type: 'object',
description:
'Additional body JSON properties that should be sent to the API endpoint.',
},
{
name: 'data',
type: 'JSONValue',
description: 'Additional data to be sent to the API endpoint.',
},
],
},
],
},
{
name: 'reload',
Expand Down Expand Up @@ -199,41 +223,29 @@ Allows you to easily create a conversational user interface for your chatbot app
},
{
name: 'handleSubmit',
type: '(event?: { preventDefault?: () => void }, chatRequestOptions?: ChatRequestOptions) => void',
type: '(event?: { preventDefault?: () => void }, options?: ChatRequestOptions) => void',
description:
'Form submission handler that automatically resets the input field and appends a user message. You can use the `options` parameter to send additional data, headers and more to the server.',
properties: [
{
type: 'ChatRequestOptions',
parameters: [
{
name: 'options',
type: 'RequestOptions',
description: 'The options to be passed to the fetch call.',
properties: [
{
type: 'ChatRequestOptions',
parameters: [
{
name: 'headers',
type: 'Record<string, string> | Headers',
description:
'An optional object of headers to be passed to the API endpoint.',
},
{
name: 'body',
type: 'object',
description:
'An optional object to be passed to the API endpoint.',
},
],
},
],
name: 'headers',
type: 'Record<string, string> | Headers',
description:
'Additional headers that should be to be passed to the API endpoint.',
},
{
name: 'body',
type: 'object',
description:
'Additional body JSON properties that should be sent to the API endpoint.',
},
{
name: 'data',
type: 'JSONValue',
description: 'Additional data to be sent to the server.',
description: 'Additional data to be sent to the API endpoint.',
},
],
},
Expand Down
24 changes: 20 additions & 4 deletions packages/core/svelte/use-chat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ const getStreamedResponse = async (
messages: constructedMessagesPayload,
data: chatRequest.data,
...extraMetadata.body,
...chatRequest.options?.body,
...chatRequest.body,
...(chatRequest.functions !== undefined && {
functions: chatRequest.functions,
}),
Expand All @@ -137,7 +137,7 @@ const getStreamedResponse = async (
credentials: extraMetadata.credentials,
headers: {
...extraMetadata.headers,
...chatRequest.options?.headers,
...chatRequest.headers,
},
abortController: () => abortControllerRef,
restoreMessagesOnFailure() {
Expand Down Expand Up @@ -284,15 +284,24 @@ export function useChat({
tools,
tool_choice,
data,
headers,
body,
}: ChatRequestOptions = {},
) => {
if (!message.id) {
message.id = generateId();
}

const requestOptions = {
headers: headers ?? options?.headers,
body: body ?? options?.body,
};

const chatRequest: ChatRequest = {
messages: get(messages).concat(message as Message),
options,
options: requestOptions,
headers: requestOptions.headers,
body: requestOptions.body,
data,
...(functions !== undefined && { functions }),
...(function_call !== undefined && { function_call }),
Expand Down Expand Up @@ -358,6 +367,11 @@ export function useChat({
event?.preventDefault?.();
const inputValue = get(input);

const requestOptions = {
headers: options.headers ?? options.options?.headers,
body: options.body ?? options.options?.body,
};

const chatRequest: ChatRequest = {
messages: inputValue
? get(messages).concat({
Expand All @@ -367,7 +381,9 @@ export function useChat({
createdAt: new Date(),
} as Message)
: get(messages),
options: options.options,
options: requestOptions,
body: requestOptions.body,
headers: requestOptions.headers,
data: options.data,
};

Expand Down
26 changes: 21 additions & 5 deletions packages/react/src/use-chat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,12 +134,12 @@ const getStreamedResponse = async (
body: experimental_prepareRequestBody?.({
messages: chatRequest.messages,
requestData: chatRequest.data,
requestBody: chatRequest.options?.body,
requestBody: chatRequest.body,
}) ?? {
messages: constructedMessagesPayload,
data: chatRequest.data,
...extraMetadataRef.current.body,
...chatRequest.options?.body,
...chatRequest.body,
...(chatRequest.functions !== undefined && {
functions: chatRequest.functions,
}),
Expand All @@ -157,7 +157,7 @@ const getStreamedResponse = async (
credentials: extraMetadataRef.current.credentials,
headers: {
...extraMetadataRef.current.headers,
...chatRequest.options?.headers,
...chatRequest.headers,
},
abortController: () => abortControllerRef.current,
restoreMessagesOnFailure() {
Expand Down Expand Up @@ -420,15 +420,24 @@ By default, it's set to 0, which will disable the feature.
tools,
tool_choice,
data,
headers,
body,
}: ChatRequestOptions = {},
) => {
if (!message.id) {
message.id = generateId();
}

const requestOptions = {
headers: headers ?? options?.headers,
body: body ?? options?.body,
};

const chatRequest: ChatRequest = {
messages: messagesRef.current.concat(message as Message),
options,
options: requestOptions,
headers: requestOptions.headers,
body: requestOptions.body,
data,
...(functions !== undefined && { functions }),
...(function_call !== undefined && { function_call }),
Expand Down Expand Up @@ -513,6 +522,11 @@ By default, it's set to 0, which will disable the feature.

event?.preventDefault?.();

const requestOptions = {
headers: options.headers ?? options.options?.headers,
body: options.body ?? options.options?.body,
};

const chatRequest: ChatRequest = {
messages: input
? messagesRef.current.concat({
Expand All @@ -521,7 +535,9 @@ By default, it's set to 0, which will disable the feature.
content: input,
})
: messagesRef.current,
options: options.options,
options: requestOptions,
headers: requestOptions.headers,
body: requestOptions.body,
data: options.data,
};

Expand Down
8 changes: 3 additions & 5 deletions packages/react/src/use-chat.ui.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -227,12 +227,12 @@ describe('form actions', () => {
</div>
))}

<form onSubmit={handleSubmit} className="fixed bottom-0 p-2 w-full">
<form onSubmit={handleSubmit} className="fixed bottom-0 w-full p-2">
<input
value={input}
placeholder="Send message..."
onChange={handleInputChange}
className="bg-zinc-100 w-full p-2"
className="w-full p-2 bg-zinc-100"
disabled={isLoading}
data-testid="do-input"
/>
Expand Down Expand Up @@ -311,9 +311,7 @@ describe('prepareRequestBody', () => {
{ role: 'user', content: 'hi' },
{
data: { 'test-data-key': 'test-data-value' },
options: {
body: { 'request-body-key': 'request-body-value' },
},
body: { 'request-body-key': 'request-body-value' },
},
);
}}
Expand Down
24 changes: 19 additions & 5 deletions packages/solid/src/use-chat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,13 +129,13 @@ const getStreamedResponse = async (
messages: constructedMessagesPayload,
data: chatRequest.data,
...extraMetadata.body,
...chatRequest.options?.body,
...chatRequest.body,
},
streamMode,
credentials: extraMetadata.credentials,
headers: {
...extraMetadata.headers,
...chatRequest.options?.headers,
...chatRequest.headers,
},
abortController: () => abortController,
restoreMessagesOnFailure() {
Expand Down Expand Up @@ -307,15 +307,22 @@ export function useChat(

const append: UseChatHelpers['append'] = async (
message,
{ options, data } = {},
{ options, data, headers, body } = {},
) => {
if (!message.id) {
message.id = generateId()();
}

const requestOptions = {
headers: headers ?? options?.headers,
body: body ?? options?.body,
};

const chatRequest: ChatRequest = {
messages: messagesRef.concat(message as Message),
options,
options: requestOptions,
headers: requestOptions.headers,
body: requestOptions.body,
data,
};

Expand Down Expand Up @@ -375,6 +382,11 @@ export function useChat(
event?.preventDefault?.();
const inputValue = input();

const requestOptions = {
headers: options.headers ?? options.options?.headers,
body: options.body ?? options.options?.body,
};

const chatRequest: ChatRequest = {
messages: inputValue
? messagesRef.concat({
Expand All @@ -384,7 +396,9 @@ export function useChat(
createdAt: new Date(),
})
: messagesRef,
options: options.options,
options: requestOptions,
body: requestOptions.body,
headers: requestOptions.headers,
data: options.data,
};

Expand Down
Loading

0 comments on commit 56bbc2a

Please sign in to comment.