콘텐츠로 이동

세션 생명주기

대화는 자신의 세션 id 아래 디스크에 남아 있으므로, 나중의 프로세스가 그것을 이어갈 수 있습니다.

const command = Command.open(Claude, { workingDir: '/proj' });
await command.setMessage('Start the refactor').send();
const sessionId = command.sessionId; // 이것을 보관해 둘 것
command.close();
// 한참 뒤, 완전히 다른 프로세스에서.
const resumed = Command.resume(sessionId, Claude, { workingDir: '/proj' });
await resumed.setMessage('Carry on where we left off').send();

대화가 새것인지 이어지는 것인지는 명시적으로 진술되며, id가 있다는 사실로부터 추론되지 않습니다. 모든 command가 id를 갖고 있으므로, 추론했다가는 전부 재개처럼 보일 것입니다 — 그리고 CLI에게 본 적 없는 id를 재개하라고 하면 No conversation found로 그대로 실패합니다.

이 둘은 서로 다른 행위이며, 혼동해서는 안 됩니다.

command.interrupt(); // 턴을 멈추고, 대화는 유지
command.close(); // CLI와 그것이 spawn한 모든 것을 종료

가정이 아니라 claude 2.1.170을 상대로 실측한 결과입니다. CLI는 control 채널에서 응답하고, subtype이 error_during_executionResultEvent로 턴을 끝냅니다 — 여기서 이것은 고장이 아니라 인터럽트됨을 뜻합니다. 프로세스는 그 뒤로도 떠 있지만 더 이상 메시지를 처리하지 않습니다. 이후에 보낸 턴은 아무 응답도 받지 못합니다.

그래서 호스트가 원하는 순서는 인터럽트, 그다음 종료, 그다음 재개입니다.

command.interrupt();
command.close();
const next = Command.resume(command.sessionId, Claude, { workingDir: '/proj' });
await next.setMessage('Try a different approach').send();

대화는 디스크에 살아남고, 소진되는 것은 이 프로세스뿐입니다. 그래도 인터럽트하는 편이 close()만 부르는 것보다 낫습니다. CLI가 쓰기 도중에 죽는 대신 자신의 결과를 기록하고 트랜스크립트 항목을 닫기 때문입니다.

Command는 자신이 구동하는 세션을 노출하는데, 이는 구동이 아니라 관찰을 위한 것입니다.

command.isLive(); // 지금 CLI 프로세스가 실행 중인지 여부
command.sessionId; // 대화의 id
command.session; // Session | null — pid, mode, stderr
command.session?.diagnostics; // CLI가 stderr에 쓴 것

CLI가 시작에 실패했을 때 손을 뻗어야 할 것이 diagnostics입니다. 프로토콜 스트림은 실행이 에러였다는 result를 실어 나르지만, 그 이유 — 잘못된 플래그, 누락된 로그인, 버전 불일치 — 는 stderr에 있고 다른 어디에도 없습니다.