agents
Version:
A home for your AI agents
333 lines (332 loc) • 11 kB
TypeScript
//#region src/harness/store/store.d.ts
/**
* A session store for harnesses, on a Durable Object's SQLite database.
*
* Any harness that runs its agent somewhere other than the object (a
* container, a sandbox, a remote process) needs the same few things kept
* durably next to it: which sessions exist, which operations were submitted
* and how each one ended, and the session's history in whatever format the
* harness speaks. This store keeps those and nothing more. It knows no
* message format, no event vocabulary and no runtime: inputs, results,
* session state and log entries are opaque JSON that the harness parses.
*
* Three record kinds:
*
* - **Sessions**: an id, an optional parent (a fork), and one JSON state
* value the harness owns (model, cursors, resume handles).
* - **Operations**: one row per submitted operation, keyed by an
* idempotency id within its session, moving `queued` → `running` →
* `done` | `unanswered`. Transitions are guarded in SQL, so a duplicate or
* late transition is a no-op rather than a regression.
* - **Logs**: named, append-ordered streams of JSON entries per session
* (`"messages"`, `"engine"`, …). An entry may carry an id, and an entry
* written again under the same id replaces the old one in place. Entries
* larger than one SQLite row are split across continuation rows.
*
* The store is synchronous, like the SQL API under it, so a harness can
* group several writes in `transaction()` without awaiting.
*
* @experimental The API may change before it stabilizes.
*/
/** A JSON value, as the store keeps it. */
type JsonValue =
| string
| number
| boolean
| null
| readonly JsonValue[]
| {
readonly [key: string]: JsonValue;
};
/** Where an operation is in its life. */
type OperationStatus = "queued" | "running" | "done" | "unanswered";
/** A session, as stored. */
type SessionRecord = {
readonly id: string /** The session this one was forked from. */;
readonly parent:
| string
| undefined /** Harness-owned state. `null` until the harness writes some. */;
readonly state: JsonValue;
readonly createdAt: number;
readonly updatedAt: number;
};
/** One operation, as stored. */
type OperationRecord = {
readonly session: string /** The idempotency key, unique within the session. */;
readonly id: string /** Submission order within the whole store. */;
readonly seq: number;
readonly status: OperationStatus /** What was submitted, in the harness's format. */;
readonly input: JsonValue /** Harness-owned submission options and bookkeeping. */;
readonly meta: JsonValue /** The harness's result for a `done` operation, else `null`. */;
readonly result: JsonValue /** Why an `unanswered` operation ended. */;
readonly reason: string | undefined;
readonly createdAt: number;
readonly settledAt: number | undefined;
};
/** One log entry, as stored. */
type LogEntry = {
/** Position in the log. Stable when the entry is replaced by id. */ readonly seq: number;
readonly id: string | undefined;
readonly data: JsonValue;
readonly createdAt: number;
};
/** One entry to append. */
type LogAppend = {
/** Replace an existing entry with this id in place, instead of appending. */ readonly id?: string;
readonly data: JsonValue;
};
/** How an operation ended. */
type OperationOutcome =
| {
readonly status: "done";
readonly result: JsonValue;
}
| {
readonly status: "unanswered";
readonly reason: string;
};
/** `openHarnessStore`'s options. */
type HarnessStoreOptions = {
/**
* Prefix for the store's tables. Two harnesses in one object use two
* prefixes. Must not start with `_cf_`, which Durable Objects reserve.
* Default `harness_`.
*/
readonly prefix?: string;
};
/**
* Open the store over this object's SQLite database, creating its tables on
* first use. Cheap: call it once per isolate and keep the result.
*
* @param storage - The Durable Object's storage.
* @param options - Table prefix.
* @returns The store.
*/
declare function openHarnessStore(
storage: DurableObjectStorage,
options?: HarnessStoreOptions
): HarnessStore;
/**
* The store. Construct it with `openHarnessStore`.
*
* @experimental The API may change before it stabilizes.
*/
declare class HarnessStore {
#private;
/**
* @param storage - The Durable Object's storage.
* @param options - Table prefix.
*/
constructor(storage: DurableObjectStorage, options: HarnessStoreOptions);
/**
* Run `fn` in one storage transaction. Writes inside it commit together or
* not at all.
*
* @template T - What `fn` returns.
* @param fn - Synchronous work against this store.
* @returns What `fn` returned.
*/
transaction<T>(fn: () => T): T;
/**
* Create a session, or return the existing one with this id unchanged.
*
* @param input - The id, an optional parent, and the initial state.
* `createdAt` keeps the creation time of a session imported from
* elsewhere, so the session list stays in creation order; default now.
* @returns The stored session.
*/
createSession(input: {
readonly id: string;
readonly parent?: string;
readonly state?: JsonValue;
readonly createdAt?: number;
}): SessionRecord;
/**
* Read one session.
*
* @param id - The session id.
* @returns The session, or `undefined` when there is none.
*/
session(id: string): SessionRecord | undefined;
/**
* Every session, oldest first.
*
* @returns The sessions.
*/
sessions(): SessionRecord[];
/**
* Replace a session's harness-owned state.
*
* @param id - The session id.
* @param state - The new state.
* @returns False when there is no such session.
*/
setSessionState(id: string, state: JsonValue): boolean;
/**
* Delete a session with its operations and logs.
*
* @param id - The session id.
* @returns False when there was no such session.
*/
deleteSession(id: string): boolean;
/**
* Durably queue an operation. Idempotent on `(session, id)`: a second
* enqueue with the same id stores nothing and returns the first record.
*
* @param input - The session, the idempotency id, the input and options.
* @returns The stored record, and whether this call created it.
*/
enqueue(input: {
readonly session: string;
readonly id: string;
readonly input: JsonValue;
readonly meta?: JsonValue;
}): {
readonly record: OperationRecord;
readonly accepted: boolean;
};
/**
* Read one operation.
*
* @param session - The session id.
* @param id - The operation id.
* @returns The operation, or `undefined` when there is none.
*/
operation(session: string, id: string): OperationRecord | undefined;
/**
* Operations in submission order, optionally narrowed to one session and
* to some statuses.
*
* @param filter - The session and statuses to keep. Default: all.
* @returns The matching operations, oldest first.
*/
operations(filter?: {
readonly session?: string;
readonly status?: readonly OperationStatus[];
}): OperationRecord[];
/**
* Move a queued operation to `running`.
*
* @param session - The session id.
* @param id - The operation id.
* @returns False when it was not queued.
*/
start(session: string, id: string): boolean;
/**
* Move a running operation back to `queued`, to run it again.
*
* @param session - The session id.
* @param id - The operation id.
* @returns False when it was not running.
*/
requeue(session: string, id: string): boolean;
/**
* Settle a queued or running operation.
*
* @param session - The session id.
* @param id - The operation id.
* @param outcome - How it ended.
* @returns False when it had already settled or does not exist.
*/
settle(session: string, id: string, outcome: OperationOutcome): boolean;
/**
* Delete one operation, whatever its status. Its id may be enqueued
* again. For replacing a record imported from elsewhere; a harness that
* deletes an open operation must stop running it itself.
*
* @param session - The session id.
* @param id - The operation id.
* @returns False when there was no such operation.
*/
deleteOperation(session: string, id: string): boolean;
/**
* Forget a session's settled operations, as when the session starts
* over. Open operations are kept. A forgotten operation's id may be
* enqueued again.
*
* @param session - The session id.
* @returns How many operations were deleted.
*/
deleteSettled(session: string): number;
/**
* Replace an operation's harness-owned bookkeeping.
*
* @param session - The session id.
* @param id - The operation id.
* @param meta - The new value.
* @returns False when there is no such operation.
*/
setOperationMeta(session: string, id: string, meta: JsonValue): boolean;
/**
* Append entries to a session's log. An entry with an id that is already
* in the log replaces that entry in place, keeping its position.
*
* @param session - The session id.
* @param log - The log's name, such as `"messages"`.
* @param entries - The entries, in order.
* @returns The position of the last entry written, or of the log's end.
*/
append(session: string, log: string, entries: readonly LogAppend[]): number;
/**
* Read a session's log in order.
*
* @param session - The session id.
* @param log - The log's name.
* @param range - Entries after position `after` (exclusive), at most `limit`.
* @returns The entries.
*/
read(
session: string,
log: string,
range?: {
readonly after?: number;
readonly limit?: number;
}
): LogEntry[];
/**
* One entry by id.
*
* @param session - The session id.
* @param log - The log's name.
* @param id - The entry id.
* @returns The entry, or `undefined`.
*/
entry(session: string, log: string, id: string): LogEntry | undefined;
/**
* The position of a log's last entry.
*
* @param session - The session id.
* @param log - The log's name.
* @returns The position, or 0 for an empty log.
*/
end(session: string, log: string): number;
/**
* Empty a session's log.
*
* @param session - The session id.
* @param log - The log's name.
*/
clear(session: string, log: string): void;
/**
* Copy one session's log onto the end of another's, keeping entry ids.
*
* @param from - The source session.
* @param to - The target session.
* @param log - The log's name.
*/
copy(from: string, to: string, log: string): void;
}
//#endregion
export {
LogEntry as a,
OperationStatus as c,
LogAppend as i,
SessionRecord as l,
HarnessStoreOptions as n,
OperationOutcome as o,
JsonValue as r,
OperationRecord as s,
HarnessStore as t,
openHarnessStore as u
};
//# sourceMappingURL=store-BKM4Xm9M.d.ts.map