본문으로 건너뛰기

버전에서 브랜치 만들기

사용자가 이전 워크스페이스에서 새 아이디어를 시도하려고 합니다. 원본 스레드는 변경되지 않은 상태로 유지되어야 합니다. snapshots.fork는 선택한 체크포인트 하나를 빈 대상 스레드에 복사합니다.

이 메서드는 전달한 체크포인트를 복사합니다. 해당 id를 전달하지 않는 한 최신 체크포인트를 복사하지 않습니다.

체크포인트 저장소는 forkFromCheckpoint를 구현해야 합니다. 이 작업은 다음 항목을 한 단계로 복사해야 합니다.

  • 선택한 체크포인트
  • 대화
  • 대상 헤드
  • blob 참조 횟수

저장소는 이미 영속 상태가 있는 대상 스레드를 거부해야 합니다.

이 라우트는 서버에 유지합니다. 세션이 원본 스레드에 액세스할 수 있고 대상 스레드를 만들 수 있는지 확인한 다음 snapshots.fork를 호출합니다.

import { requireSession } from './auth'
import { snapshots } from './sandbox-server'

export async function POST(request: Request) {
const session = await requireSession(request)
let payload: unknown
try {
payload = await request.json()
} catch {
return new Response('Invalid request', { status: 400 })
}
if (
payload === null ||
typeof payload !== 'object' ||
!('threadId' in payload) ||
!('checkpointId' in payload) ||
!('destinationThreadId' in payload) ||
typeof payload.threadId !== 'string' ||
typeof payload.checkpointId !== 'string' ||
typeof payload.destinationThreadId !== 'string'
) {
return new Response('Invalid request', { status: 400 })
}
const threadId = payload.threadId
const checkpointId = payload.checkpointId
const destinationThreadId = payload.destinationThreadId
if (!(await session.canAccessThread(threadId))) {
return new Response('Not found', { status: 404 })
}
if (!(await session.canCreateThread(destinationThreadId))) {
return new Response('Not found', { status: 404 })
}

const checkpoint = await snapshots.fork({
threadId,
checkpointId,
destinationThreadId,
})

return Response.json({ checkpointId: checkpoint.id })
}

클라이언트는 이 라우트로 요청을 보냅니다. snapshots.fork를 호출하지 않습니다.

export async function forkCheckpoint(
threadId: string,
checkpointId: string,
destinationThreadId: string,
) {
const response = await fetch('/api/snapshots/fork', {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify({
threadId,
checkpointId,
destinationThreadId,
}),
})
if (!response.ok) throw new Error('Could not fork checkpoint')
return response.json()
}

두 스레드에 동일한 권한 부여 규칙을 사용합니다. 클라이언트가 선택한 체크포인트 id는 액세스 권한의 증명이 아닙니다.

예제에서 확인하기

React 채팅 예제에는 /app-studio의 App Studio 페이지가 있습니다. 이 페이지는 하나의 프롬프트에서 시작해 실시간 미리 보기를 표시한 다음, 채팅을 포크하거나 두 방향을 비교할 수 있게 합니다.

  1. examples/ts-react-chat을 엽니다.
  2. XAI_API_KEY를 설정하고 Docker를 시작합니다.
  3. pnpm dev를 실행하고 /app-studio를 엽니다.
  4. 앱을 빌드합니다. 그런 다음 채팅 포크 또는 두 방향 비교를 사용합니다.

두 방향 비교를 선택하고 제출하면 페이지가 /api/app-studio-fork를 호출하며 count: 2를 전달합니다. 각 포크는 새 샌드박스와 원본 스레드의 저장된 파일을 받습니다. node_modules가 없으면 에이전트가 종속성을 설치한 다음 미리 보기를 시작합니다. 각 창에는 자체 미리 보기 URL이 표시됩니다. 하나의 브랜치를 유지합니다. 원본 스레드는 변경되지 않은 상태로 유지됩니다.

examples/ts-react-chat/README.md의 App Studio 섹션을 참조합니다. 페이지 경로는 /app-studio입니다.

SQLite를 사용하는 경우 포크를 하나의 트랜잭션으로 처리합니다. 해당 트랜잭션은 원본 대화를 복사하고 비어 있지 않은 대상 스레드를 거부해야 합니다. 다시 로드한 후에도 파일 유지를 참조합니다.

에이전트가 직접 포크를 호출해야 하는 경우 에이전트가 저장하고 포크하도록 허용을 사용합니다.