첫 세션 만들기
SDK로 세션을 만들고, turn이 끝나길 기다려 모델의 답을 읽는다
SDK 설치에서 만든 werft 클라이언트로 세션 하나를 만들고 첫 turn이 끝나는 것까지 본다. 예제는 개발용 서버를 --fake-model로 띄운 경우다. GATE-SPEC {…} 메시지는 fake 모델이 읽는 대본이라, 실제 Claude가 도는 서버에서는 평범한 문장을 보낸다.
프로필 고르기
세션은 서버 운영자가 등록한 프로필(profile) 중 하나로 돈다. 연결 확인에서 본 목록이다. 개발용 서버에는 저장소를 쓰는 claude-coding-local(권한 요청에 사람이 답한다)과 claude-coding-auto(분류기가 판정한다), 저장소 없이 도는 general이 있다. 여기서는 claude-coding-local을 쓴다.
세션 만들기
import { waitForTurn } from "@werft-ai/sdk";
import { werft } from "./werft.ts";
const created = await werft.sessions.create({
profile_id: "claude-coding-local",
repository_id: "sample-app",
message: 'GATE-SPEC {"id":"hello","steps":[],"final":"hello from Werft"}',
});
console.log(created);{
session_id: '…',
turn_id: '1',
receipt_id: '…',
receipt_status: 'accepted',
status: 'queued'
}repository_id는 세션이 clone할 저장소다. 개발용 서버의 읽기 전용 Git 서버가sample-app을 내준다.message는 첫 turn의 입력이다. 이 대본은 도구를 부르지 않고hello from Werft로 끝난다.- 만들기는 접수만 한다. 결과는 turn이 끝난 뒤에 읽는다.
- 세션을 만드는 요청에는
Idempotency-Key가 필요하다. SDK가 호출마다 하나 만들어 붙이고, 그 호출을 재시도할 때 같은 key를 다시 보낸다.
turn 끝나기 기다리기
scheduler가 worker를 띄우고 worker가 저장소를 clone한 뒤 turn 1을 돈다. 처음에는 수십 초 걸린다.
const turn = await waitForTurn(werft, created.session_id, created.turn_id, {
signal: AbortSignal.timeout(5 * 60_000),
});
console.log(`turn ${turn.turn_id}: ${turn.status}`);turn 1: completedwaitForTurn은 turn의 status가 끝난 값이 될 때까지 2초마다 확인한다. completed·failed·interrupted·cancelled·outcome_unknown이 끝난 상태다. failed도 오류가 아니라 status 값이므로 일이 됐는지는 이벤트로 판단한다.
모델의 답 보기
세션에서 일어난 일은 이벤트 스트림으로 온다. 스트림은 turn이 끝나도 닫히지 않으므로 필요한 이벤트를 받으면 직접 끝낸다.
const stream = werft.sessions.events.stream(created.session_id);
for await (const event of stream) {
if (event.kind === "assistant") {
console.log((event.payload as { text?: string }).text);
}
if (event.kind === "result") break;
}
stream.close();hello from Werftassistant 이벤트의 text가 모델이 보낸 텍스트다. 세 조각을 이어 붙인 first-session.ts를 WERFT_API_KEY=csp_… node first-session.ts로 돌리면 위 출력이 차례로 나온다.
HTTP API로 할 때
같은 흐름은 POST /v1/sessions(Idempotency-Key 헤더 필요), GET /v1/sessions/{id}/turns/{turn_id} 폴링, GET /v1/sessions/{id}/events(SSE)다.