마이그레이션
TanStack AI 는 이제 승인, 일반적인 일시 중지 및 클라이언트-도구 실행을
AG-UI 인터럽트 설명자로 모델링합니다. 네이티브 실행은
RUN_FINISHED.outcome.type === 'interrupt'로 종료되며, 계속되는 실행은 중단된 실행의
parentRunId입니다.
codemod는 없습니다. 서버 수명 주기와 클라이언트 렌더링을 함께 마이그레이션합니다. 레거시 리더는 이전 스트림을 위해 임시로 유지되지만 전체 네이티브 계약을 제공할 수 없습니다. 개요에서 시작합니다.
API 매핑
| 지원 중단 / 레거시 | 현재 |
|---|---|
pendingInterrupts | interrupts(pendingInterrupts은 같은 배열을 가리키는 지원 중단 예정 별칭) |
ChatClient.getPendingInterrupts() | ChatClient.getInterrupts() |
addToolApprovalResponse({ id, approved }) | 바인딩된 tool-approval 항목을 찾아 interrupt.resolveInterrupt(approved) 호출 |
원시 resumeInterrupts(entries, state) | 바인딩된 항목 메서드 또는 루트 resolveInterrupts(...) 사용. 검증된 복구 도구에만 resumeInterruptsUnsafe 사용 |
approval-requested 커스텀 이벤트 | RUN_FINISHED 인터럽트 디스크립터, 이유 tool_call |
tool-input-available 커스텀 이벤트 | RUN_FINISHED 인터럽트 디스크립터, 이유 tanstack:client_tool_execution |
| 불리언 거부를 취소로 처리 | 거부에는 resolveInterrupt(false), payload 없는 취소에는 cancel() 사용 |
addToolResult는 제거되지 않습니다. 여전히 클라이언트 도구 결과를 처리하고 일치하는 네이티브 항목에 위임합니다. needsApproval은 승인에 사용하는 도구 정의 스위치로 계속 유지됩니다.
단일 승인
// Before
await addToolApprovalResponse({ id: approval.id, approved: true })
// After
const interrupt = interrupts.find(
(item) => item.kind === 'tool-approval' && item.toolName === 'transfer',
)
if (interrupt?.kind === 'tool-approval' && interrupt.toolName === 'transfer') {
interrupt.resolveInterrupt(true)
}
유효한 단일 항목은 자동으로 제출됩니다. 전체 렌더링/해결 컴포넌트는 도구 승인을 참조합니다.
분기 페이로드와 편집
레거시 불리언 승인은 타입이 지정된 데이터를 전달할 수 없었습니다. approvalSchema를 추가하고 payload 아래의 데이터로 선택한 분기를 해결합니다.
interrupt.resolveInterrupt(true, {
editedArgs: { amount: 12, recipient: 'Ada' }, // optional, approval-only, full replacement
payload: { note: 'Reviewed' },
})
interrupt.resolveInterrupt(false, { payload: { reason: 'Policy limit' } })
거절은 편집을 수락하지 않으며, 최상위 커스텀 필드는 유효하지 않습니다. 단일 approvalSchema ( { approve, reject } 가 아님) 는 선택된 결정에 적용되며, 스키마가 없으면 부울형 약식 표현은 유효하게 유지됩니다.
거부와 취소의 차이
resolveInterrupt(false, ...) 은 명시적으로 거절된 결정으로 모델을 계속합니다. cancel() 는 AG-UI status: 'cancelled' 를 방출하며 거절 분지를 유효화하거나 선택하지 않습니다.弃용된 addToolApprovalResponse({ approved: false }) 은 거절이 아닌 취소에 매핑됩니다.
배치
네이티브 배치는 전부 성공하거나 전부 실패합니다. 승인 ID 루프를 준비된 항목(마지막 유효 항목이 자동 제출됨) 또는 하나의 동기 루트 콜백으로 교체합니다.
resolveInterrupts((interrupt) => {
if (interrupt.kind === 'tool-approval') {
interrupt.resolveInterrupt(true, { payload: { note: 'Batch review' } })
return
}
interrupt.cancel()
})
resolveInterrupts(true|false)는 페이로드/편집이 없는 전체 승인 배치에서만 사용하는 축약형입니다. 모든 항목을 페이로드 없이 취소하려면 cancelInterrupts()를 사용하고, 초안 하나를 삭제하려면 clearResolution()을 사용합니다. 모든 항목이 여전히 유효하게 준비되었고 루트 오류를 재시도할 수 있을 때만 retryInterrupts()를 사용합니다. 여러 인터럽트를 참조합니다.
일반 응답
수신한 responseSchema에서 정적 타입을 도출하지 않습니다. unknown으로 파싱하고 z.fromJSONSchema로 변환한 다음 검증된 값을 해결합니다. 전체 양식 예시는 일반 인터럽트에 있습니다.
서버 이벤트
네이티브 서버는 다음 순서로 내보냅니다: MESSAGES_SNAPSHOT → 선택적
STATE_SNAPSHOT → 비어 있지 않은 인터럽트 결과가 포함된 RUN_FINISHED.
계속 실행은 새로운 runId, 동일한 threadId, 인터럽트된 실행을 parentRunId로 사용하며 모든 보류 ID가 정확히 한 번씩 포함됩니다.
인터럽트는 일시적으로 실행됩니다. 서버는 제출된 기록과 현재 도구 정의에서 예상 배치를 재구성하고 검증하므로 상태 비저장 라우트에는 영속성이 필요하지 않습니다. 클라이언트가 제공한 입력으로 배치를 다시 구성하므로 이 모드는 권위 있는 복구, 정확히 한 번 실행, 재생 방지 또는 재시작 복구를 제공하지 않습니다.
resumeInterruptsUnsafe는 검증된 원시 재개 항목을 직접 제출하는 저수준 우회 수단이며, 승인 UI의 일반적인 대상이 아닙니다.
레거시 제한 사항
더 이상 권장되지 않는 리더는 형식이 올바른 과거 approval-requested 및
tool-input-available 이벤트를 인식하고 완전히 처리된 레거시 배치를 하나의 복제 기록 후속 실행으로 변환합니다. 편집된 인수, 사용자 지정 승인 페이로드, 일반 응답, 페이로드 없는 취소 또는 만료/스키마 해시 조정을 지원하지 않으며, 이러한 경우 legacy-unsupported로 실패합니다. 네이티브 항목과 레거시 항목은 하나의 배치에서 섞을 수 없습니다. 레거시 전송이 실패하면 준비된 결정을 유지하고 legacy-submit-failed를 보고합니다.
체크리스트
- 네이티브 커스텀 이벤트 작성기를 인터럽트 터미널로 교체합니다.
interrupts대신pendingInterrupts을 렌더링합니다.- 부울 승인 도우미를
resolveInterrupt+ 명시적 거절/취소로 교체합니다. - 승인 루프를 원자적 배치 스테이징 또는 루트
resolveInterrupts로 교체합니다. - 유용한 경우 클라이언트-도구 결과에
addToolResult를 유지합니다. - 레거시 지원을 제거하기 전에 만료된 항목과 실패한 전송을 테스트합니다.