@sema-agent/core
Version:
Stateless, task-oriented AI agent core
28 lines (27 loc) • 1.96 kB
TypeScript
import { type SessionStore } from "../session.js";
import { type ContractAssertionRunner } from "./contract-harness.js";
/**
* The cross-backend contract for the SESSION INCARNATION face ({@link SessionStore.incarnationOf}):
* the token naming WHICH occupant holds a session id. vitest-free (see `contract-harness.ts`); mount it
* on every store that implements `incarnationOf` — the face is optional on the interface, so this kit
* is a separate opt-in kit rather than a skipped case inside another one (a skipped case is how an
* unimplemented face reads green). A store WITHOUT the face fails every case loudly.
*
* The law the cases pin: the token is a cell of the session ROW, minted once when the row comes into
* existence and answered unchanged by every later read of that row — a cache forgetting the session or
* a second store over the same rows does not change it, deleting the row and handing the id out again
* does, a fork is a new occupant. A `SessionRepo` author runs it through the bundled cache layer
* (`make: () => new TtlSessionStore({ repo })`, `reopen: () => new TtlSessionStore({ repo })`).
*
* `make()` must return a FRESH, empty store each call; each case disposes the store it built.
*/
export interface SessionStoreIncarnationContractHooks {
/** Delete `sessionId`'s session ROW through the backend's own deletion path (history and all), so
* that a later `acquire(sessionId)` creates a new session under the same id. */
deleteSession: (store: SessionStore, sessionId: string) => Promise<void>;
/** A SECOND, independent store instance over the same rows as `store` — what a restarted process or
* another replica constructs. The kit disposes it. */
reopen: (store: SessionStore) => SessionStore;
runAssertion?: ContractAssertionRunner;
}
export declare function sessionStoreIncarnationContract(make: () => SessionStore, hooks: SessionStoreIncarnationContractHooks): Promise<void>;