File size: 1,966 Bytes
4e23b01 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | /**
* Higher-level wait helpers built on top of `WsClient.waitForFrame` and
* `HttpClient.getSession`. Kept separate from `client.ts` so scenarios can
* import them directly without dragging the whole `DaemonClient` class.
*/
import type { Session } from '@moonshot-ai/kap-server/protocol/session';
import type { HttpClient } from './http.js';
import type { AnyFrame, WsClient } from './ws.js';
/** Default 60s wait for a single event frame — matches approval/question TTL. */
export const DEFAULT_FRAME_TIMEOUT_MS = 60_000;
/**
* Wait for the first WS frame matching `predicate`. Thin wrapper that fills
* the default timeout — most scenarios shouldn't have to think about it.
*/
export function waitForFrame(
ws: WsClient,
predicate: (frame: AnyFrame) => boolean,
opts?: { timeoutMs?: number },
): Promise<AnyFrame> {
return ws.waitForFrame(predicate, opts?.timeoutMs ?? DEFAULT_FRAME_TIMEOUT_MS);
}
/**
* Poll `GET /sessions/{sid}` until aggregate `busy` matches. Useful as a
* final synchronization point — the server's `turn.ended` arrives before
* the session work projection flips to false, so scenarios that want a
* quiescent session must poll.
*/
export async function waitForSessionBusy(
http: HttpClient,
sid: string,
busy: boolean,
opts?: { timeoutMs?: number; pollMs?: number },
): Promise<Session> {
const timeoutMs = opts?.timeoutMs ?? DEFAULT_FRAME_TIMEOUT_MS;
const pollMs = opts?.pollMs ?? 250;
const deadline = Date.now() + timeoutMs;
let last: Session | null = null;
while (Date.now() < deadline) {
const session = await http.getSession(sid);
last = session;
if (session.busy === busy) return session;
await sleep(pollMs);
}
throw new Error(
`session ${sid} did not reach busy=${busy} within ${timeoutMs}ms ` +
`(last busy=${last?.busy ?? 'unknown'})`,
);
}
function sleep(ms: number): Promise<void> {
return new Promise((resolve) => setTimeout(resolve, ms));
}
|