createUIMessageStream — UI 메시지 스트림 만들기
createUIMessageStream — UI 메시지 스트림 만들기
createUIMessageStream 함수는 메시지 병합, 에러 처리, 완료 콜백 같은 고급 기능을 갖춘 UI 메시지용 readable stream을 만들 수 있게 해줘요. 채팅 UI 응답을 서버에서 직접 조립할 때 쓰는 함수예요.
출처: 문서
본문
createUIMessageStream 함수는 메시지 병합, 에러 처리, 완료 콜백 같은 고급 기능과 함께 UI 메시지용 readable stream을 만들 수 있게 해줘요.
Import
import { createUIMessageStream } from "ai"
예시
const existingMessages: UIMessage[] = [
/* ... */
];
const stream = createUIMessageStream({
async execute({ writer }) {
// 외부 스트림이 어시스턴트 메시지 라이프사이클을 소유해요.
writer.write({ type: 'start' });
// 텍스트 메시지 시작
// 참고: id는 text-start, text-delta, text-end 단계에서 일관되어야 해요
// 그래야 시스템이 이들이 같은 텍스트 블록에 속한다는 걸 올바르게 식별할 수 있어요
writer.write({
type: 'text-start',
id: 'example-text',
});
// 메시지 청크 쓰기
writer.write({
type: 'text-delta',
id: 'example-text',
delta: 'Hello',
});
// 텍스트 메시지 끝
writer.write({
type: 'text-end',
id: 'example-text',
});
// streamText의 다른 스트림 병합
const result = streamText({
model: __MODEL__,
prompt: 'Write a haiku about AI',
});
writer.merge(
toUIMessageStream({
stream: result.stream,
sendStart: false,
onEnd: ({ outcome }) => {
// 컴포저가 모델 스트림의 outcome이 곧
// 전체 스트림의 outcome이라고 결정해요.
writer.setOutcome(outcome);
},
}),
);
},
onError: error => `Custom error: ${error.message}`,
originalMessages: existingMessages,
onEnd: ({ messages, isContinuation, outcome, responseMessage }) => {
console.log('Stream ended with messages:', messages);
console.log('Stream outcome:', outcome.status);
},
});
setOutcome은 청크를 쓰거나 스트림을 닫지 않고 컴포저의 정책을 기록해요. setOutcome으로 선언된 첫 번째 outcome은 유지되지만, 치명적인 실행·병합·에러 처리·하위 처리 실패가 발생하면 최종 onEnd의 outcome이 failed가 돼요. 개별 error 청크는 그 자체로 outcome을 바꾸지 않아요. 여러 하위(child) 스트림을 병합할 때는 outcome을 모두 합쳐 setOutcome을 한 번만 호출하세요.
API 시그니처
파라미터
execute:(options: { writer: UIMessageStreamWriterWithOutcome }) => Promise<void> | void— writer 인스턴스를 받아 UI 메시지 청크를 스트림에 쓰는 데 사용하는 함수.write:(part: UIMessageChunk) => void— UI 메시지 청크를 스트림에 써요.merge:(stream: ReadableStream<UIMessageChunk>) => void— 다른 UI 메시지 스트림의 내용을 이 스트림으로 병합해요.setOutcome:(outcome: UIMessageStreamOutcome) => void— 구성된 스트림의 작업 수준 outcome을 선언해요. 이 메서드로 선언된 첫 번째 outcome은 유지되고, 치명적인 실행·병합·에러 처리·하위 처리 실패가 발생하면 선언을 덮어써요. 지원하는 상태는'completed','failed','aborted','unknown'이에요. outcome을 선언해도 청크를 쓰거나 스트림을 닫지 않아요.onError:(error: unknown) => string— 병합된 스트림의 에러를 처리하기 위해 스트림 writer가 사용하는 에러 핸들러.
onError:(error: unknown) => string— 에러를 처리하고 에러 메시지 문자열을 반환하는 함수. 기본값은 에러 메시지를 반환해요.originalMessages:UIMessage[] | undefined— 원본 메시지. 제공하면 영속(persistence) 모드로 간주되고 응답 메시지에 메시지 ID가 제공돼요.onEnd:(options: { messages: UIMessage[]; isContinuation: boolean; isAborted: boolean; isCancelled?: true; outcome: UIMessageStreamOutcome; responseMessage: UIMessage; finishReason?: FinishReason }) => PromiseLike<void> | void— 스트림이 끝날 때 호출되는 콜백 함수.messages:UIMessage[]— 업데이트된 UI 메시지 목록.isContinuation:boolean— 응답 메시지가 마지막 원본 메시지의 연속인지, 아니면 새 메시지가 생성됐는지를 나타내요.isAborted:boolean— 스트림이 중단됐는지 나타내요.isCancelled:true | undefined— outcome이 선언되기 전에 소비자가 스트림을 취소했을 때(예: 클라이언트 연결 해제) 존재하며 true예요.outcome:UIMessageStreamOutcome = { status: 'completed' } | { status: 'failed'; error?: unknown } | { status: 'aborted' } | { status: 'unknown' }— 스트림의 작업 수준 outcome. 치명적인 스트림 처리 실패가 없는 한 스트림 소유자의 선언을 반영하며, 모델 finish reason이나 개별 error 청크와는 별개예요. 소비자가 outcome 선언 전에 취소하면'unknown'으로 남아요. 선언된 outcome 없이 정상 종료된 경우와 구분하려면isCancelled를 확인하세요.responseMessage:UIMessage— 응답으로 클라이언트에 보내진 메시지 (확장된 원본 메시지 포함).finishReason:FinishReason | undefined— 생성이 끝난 이유.'stop','length','content-filter','tool-calls','error','other'중 하나예요.
onFinish:(options: { messages: UIMessage[]; isContinuation: boolean; isAborted: boolean; isCancelled?: true; outcome: UIMessageStreamOutcome; responseMessage: UIMessage; finishReason?: FinishReason }) => PromiseLike<void> | void—onEnd의 deprecated 별칭.generateId:IdGenerator | undefined— 메시지의 고유 ID를 생성하는 함수. 제공하지 않으면 기본 ID 생성기를 사용해요.
반환값
ReadableStream<UIMessageChunk> — UI 메시지 청크를 내보내는 readable stream을 반환해요. 스트림은 에러 전파, 여러 스트림의 병합, 모든 작업이 완료됐을 때의 적절한 정리를 자동으로 처리해요.
더 알아보기 (Learn more)
- createUIMessageStreamResponse — Response 객체로 스트리밍
- useChat — 채팅 훅