useChat와 함께 커스텀 headers, body, credentials가 동작하지 않을 때

useChat와 함께 커스텀 headers, body, credentials가 동작하지 않을 때

useChat 훅에 직접 설정한 headers, body, credentials 같은 커스텀 요청 옵션이 요청에 포함되지 않는 경우가 있어요. 이유와 해결 방법을 정리해 드릴게요.

출처: 문서

본문

문제 (Issue)

useChat 훅을 사용할 때 훅에 직접 설정한 headers, body 필드, credentials 같은 커스텀 요청 옵션이 요청에 함께 전송되지 않습니다.

// These options are not sent with the request
const { messages, sendMessage } = useChat({
  headers: {
    Authorization: 'Bearer token123',
  },
  body: {
    user_id: '123',
  },
  credentials: 'include',
});

배경 (Background)

useChat 훅은 요청 옵션을 설정하는 API가 변경되었습니다. 훅 자체에 직접 설정하는 headers, body, credentials 같은 옵션은 더 이상 지원되지 않습니다. 대신 DefaultChatTransport와 함께 transport 설정을 사용하거나 요청 레벨에서 옵션을 전달해야 합니다.

해결책 (Solution)

useChat로 요청 옵션을 제대로 설정하는 방법은 세 가지가 있습니다.

옵션 1: 요청 레벨 설정 (동적 값에 권장)

시간이 지남에 따라 변하는 동적 값에는 sendMessage를 호출할 때 옵션을 전달하는 방식이 권장됩니다.

const { messages, sendMessage } = useChat();

// Send options with each message
sendMessage(
  { text: input },
  {
    headers: {
      Authorization: *** ${getAuthToken()}`, // Dynamic auth token
      'X-Request-ID': generateRequestId(),
    },
    body: {
      temperature: 0.7,
      max_tokens: 100,
      user_id: getCurrentUserId(), // Dynamic user ID
      sessionId: getCurrentSessionId(), // Dynamic session
    },
  },
);

이 방식은 각 요청에 항상 가장 최신 값을 보낼 수 있게 해 줍니다.

옵션 2: 정적 값을 가진 훅 레벨 설정

컴포넌트 수명 동안 변하지 않는 정적 값에는 DefaultChatTransport를 사용하세요.

import { useChat } from '@ai-sdk/react';
import { DefaultChatTransport } from 'ai';

const { messages, sendMessage } = useChat({
  transport: new DefaultChatTransport({
    api: '/api/chat',
    headers: {
      'X-API-Version': 'v1', // Static API version
      'X-App-ID': 'my-app', // Static app identifier
    },
    body: {
      model: 'gpt-6-astra', // Default model
      stream: true, // Static configuration
    },
    credentials: 'include', // Static credentials policy
  }),
});

옵션 3: 함수(Resolvable) 형식의 훅 레벨 설정

훅 레벨에서 동적 값이 필요하다면 설정 값을 반환하는 함수를 사용할 수 있습니다. 다만 신뢰성 면에서는 요청 레벨 설정이 일반적으로 더 선호됩니다.

import { useChat } from '@ai-sdk/react';
import { DefaultChatTransport } from 'ai';

const { messages, sendMessage } = useChat({
  transport: new DefaultChatTransport({
    api: '/api/chat',
    headers: () => ({
      Authorization: *** ${getAuthToken()}`,
      'X-User-ID': getCurrentUserId(),
    }),
    body: () => ({
      sessionId: getCurrentSessionId(),
      preferences: getUserPreferences(),
    }),
    credentials: () => (isAuthenticated() ? 'include' : 'same-origin'),
  }),
});
시간이 지남에 따라 변하는 컴포넌트 상태라면 요청 레벨 설정(옵션 1)이 권장됩니다. 훅 레벨 함수를 사용한다면 `useRef`로 현재 값을 저장하고 구성 함수에서 `ref.current`를 참조하는 방식을 고려해 보세요.

훅 레벨과 요청 레벨 옵션 결합

요청 레벨 옵션은 훅 레벨 옵션보다 우선합니다.

// Hook-level default configuration
const { messages, sendMessage } = useChat({
  transport: new DefaultChatTransport({
    api: '/api/chat',
    headers: {
      'X-API-Version': 'v1',
    },
    body: {
      model: 'gpt-6-astra',
    },
  }),
});

// Override or add options per request
sendMessage(
  { text: input },
  {
    headers: {
      'X-API-Version': 'v2', // This overrides the hook-level header
      'X-Request-ID': '123', // This is added
    },
    body: {
      model: 'gpt-4.1-mini', // Supports the temperature setting below
      temperature: 0.5, // This is added
    },
  },
);

요청 구성에 대한 자세한 내용은 Request Configuration 문서를 참고하세요.

더 알아보기 (Learn more)