UNPKG

agents

Version:

A home for your AI agents

461 lines (459 loc) • 17.4 kB
import { a as RecentHistoryResult, c as SessionChangeListener, d as SessionRowStat, f as SessionsOptions, i as HistoryReadOptions, l as SessionMessage, m as WriteOptions, n as AppendResult, o as SearchResult, p as StoredCompaction, r as HistoryBatchReadOptions, s as SessionChangeEvent, t as AppendOptions } from "./types-B7LojTe4.js"; //#region src/sessions/compaction-helpers.d.ts /** Prefix for all compaction messages (overlays and summaries) */ declare const COMPACTION_PREFIX = "compaction_"; /** Check if a message is a compaction message */ declare function isCompactionMessage(msg: SessionMessage): boolean; /** * Result of a compaction function — describes the overlay to store. */ interface CompactResult { /** First message ID in the compacted range */ fromMessageId: string; /** Last message ID in the compacted range */ toMessageId: string; /** Summary text to store as the overlay */ summary: string; } interface CompactOptions { /** Calls the model to summarize; receives a prompt, returns its text. */ summarize: (prompt: string) => Promise<string>; /** * Token budget for the recent tail kept verbatim. Older messages above the * protected head are summarized into one overlay. Default 20,000. */ keepRecentTokens?: number; } /** * Reference compaction implementation. * * Implements the full hermes-style compaction algorithm: * 1. Protect head messages (first N) * 2. Protect tail by token budget (walk backward) * 3. Align boundaries to tool call groups * 4. Summarize middle section with LLM (structured format) * 5. Iterative summary updates on subsequent compactions * * @example * ```typescript * import { createCompactFunction } from "agents/sessions"; * * sessions * .session() * .onCompaction( * createCompactFunction({ * summarize: (prompt) => generateText({ model, prompt }).then((r) => r.text) * }) * ) * .compactAfter(100_000); * ``` */ declare function createCompactFunction( opts: CompactOptions ): (messages: SessionMessage[]) => Promise<CompactResult | null>; //#endregion //#region src/sessions/io.d.ts /** @internal SQLite and telemetry supplied by the Sessions capability. */ type SqlParam = ArrayBuffer | string | number | null; interface SessionsIo { /** Run a read and return every row. */ sql<T>(query: string, params: SqlParam[]): T[]; /** Run a write (or DDL) and return the rows it wrote. */ sqlWrite(query: string, params: SqlParam[]): number; /** One synchronous SQLite transaction. */ transaction<T>(fn: () => T): T; /** Capability telemetry event. */ emit(type: string, payload: Record<string, unknown>): void; } //#endregion //#region src/sessions/core.d.ts type UpdateOutcome = "missing" | "unchanged" | "updated"; declare class SessionsCore { #private; readonly io: SessionsIo; constructor(options: SessionsOptions, io: SessionsIo); ensureTables(): void; /** * Lift the legacy `assistant_*` message and compaction tables. * * The copy is pure SQL, so SQLite streams it rather than materializing rows * in the isolate. Each source is then verified row by row against its * destination and DROPPED: keeping tombstones would leave every upgraded * object holding its history twice inside the same 10 GB. A table whose * verification fails is left in place with a `session:migration:incomplete` * event, and the method returns false so the caller leaves the schema * version unstamped and retries on a later start. `assistant_config` * belongs to Think, which lifts and drops it itself. */ migrateLegacy(): boolean; subscribe(listener: SessionChangeListener): () => void; /** * Dispatch after a durable write. A listener that throws must not turn a * committed write into a rejected call, so failures are reported through * telemetry and dispatch continues. */ notify(event: SessionChangeEvent): Promise<void>; exists(sessionId: string, id: string): boolean; getMessage(sessionId: string, id: string): SessionMessage | null; /** * Drop the in-memory tail and token-total caches for a session. For a * caller whose enclosing transaction rolled back after an append or update * ran inside it: the rows are gone but the caches already moved. The next * read re-derives both from storage. */ forgetCaches(sessionId: string): void; latestLeafId(sessionId: string): string | null; getLatestLeaf(sessionId: string): SessionMessage | null; getBranches(sessionId: string, messageId: string): SessionMessage[]; /** * The active branch path as content-free rows, root → leaf. Recurses over * (id, parent_id) only — carrying content through the recursive queue * materializes the transcript several times inside SQLite (#1710). * `bytes` counts the message row, its continuation rows, AND the payloads * it points at, charged at the size they take once inlined, so a byte * budget over these rows bounds real hydrated memory. */ pathRowStats(sessionId: string, leafId?: string | null): SessionRowStat[]; /** * Stream the path ending at `leafId` (default: active leaf), root → leaf * (or leaf → root with `newestFirst`), compaction overlays collapsed. Peak * memory is one bounded content window — never the whole transcript. */ streamHistory( sessionId: string, options: HistoryReadOptions ): AsyncGenerator<SessionMessage, void, undefined>; getHistory( sessionId: string, options: HistoryReadOptions ): Promise<SessionMessage[]>; /** * Byte-budgeted read of the most recent messages on the active branch * path — the longest suffix whose stored size fits `maxContentBytes`. * * There is no message-count floor: one used to exist, and it admitted * rows regardless of size, so a window of media-heavy messages could * hydrate far past the limit meant to bound it. The newest message is * always returned even if it alone exceeds the budget, since returning * nothing is worse. Overlays whose anchors fall outside the window are * skipped, showing the raw recent messages. */ getRecentHistory( sessionId: string, maxContentBytes: number, leafId?: string | null ): Promise<RecentHistoryResult>; /** * Heuristic token estimate for the active path with compaction overlays * applied: stamped per-row estimates, minus compacted spans, plus their * summaries. Derived from content-free rows on each call; it gates cheap * triggers only, and model-reported usage stays authoritative. */ tokenEstimate(sessionId: string): number; stripReservedMetadata(message: SessionMessage): SessionMessage; /** * Stamped row estimate: the part heuristic over the message as written, * plus a weight per inline file payload so media never counts as zero. */ estimateRowTokens(message: SessionMessage): number; /** * Durable append. The caller has already sanitized the message. Message, * continuation, attachment, and FTS rows commit in one synchronous SQLite * transaction. Returns the stored message: the input itself when it was * inserted (extraction is lossless, so the two are identical), or the row * already holding the id when it was not. */ append( sessionId: string, message: SessionMessage, parentId: string | null | undefined, tokenEstimate: number ): { inserted: boolean; message: SessionMessage; }; /** * Durable update of an existing row. An identical row writes nothing: no * row, no continuation, no FTS, no event. The no-op guard compares the * FULL content, through the digest the last write stamped, so neither the * payload nor a continuation row is read. A row without a digest compares * the reassembled content once and is stamped. */ update( sessionId: string, message: SessionMessage, tokenEstimate: number ): UpdateOutcome; /** * Delete rows, SPLICING children to their grandparent so a mid-chain * delete never decapitates older history. Only surviving boundary children * are rewired: a prefix delete writes one boundary child, not one child * per deleted message. */ deleteMessages(sessionId: string, messageIds: string[]): void; clearMessages(sessionId: string): void; addCompaction( sessionId: string, summary: string, fromMessageId: string, toMessageId: string ): StoredCompaction; getCompactions(sessionId: string): StoredCompaction[]; search(sessionId: string, query: string, limit: number): SearchResult[]; /** * Import one historical message verbatim (migrations, cross-DO moves): * explicit parent and timestamp, stamped estimate, no change-feed events. */ /** Returns `false` when the id already exists and nothing was written. */ importMessage( sessionId: string, message: SessionMessage, options: { parentId: string | null; createdAt: number; } ): boolean; } //#endregion //#region src/sessions/mirror.d.ts /** * How a host keeps an in-memory transcript in step with one session's change * feed. The mirror applies the reduction every such cache needs; the hooks * carry the decisions only the host can make. */ interface SessionMirrorOptions< M extends { id: string; } > { /** * The cached transcript. Read on every event, so a host that reassigns its * array (a public `messages` field, say) is followed rather than * shadowed. */ get(): M[]; /** Install a new array: after a delete, or emptied by a clear. */ set(messages: M[]): void; /** The cached form of a stored message. Defaults to the stored message. */ transform?(message: SessionMessage): M; /** * Handle an event instead of the default reduction, returning `true` when * it did. A host whose cache cannot express a change in place — a branch * append, a compaction — re-reads storage here. */ intercept?(event: SessionChangeEvent): boolean | Promise<boolean>; /** * After the default reduction wrote `message` for an append or update. * `previous` is the cached entry it replaced, if there was one. */ onApplied?( event: Extract< SessionChangeEvent, { type: "append" | "update"; } >, message: M, previous: M | undefined ): void; } //#endregion //#region src/sessions/handle.d.ts /** Summarizes a branch into an overlay. */ type CompactionFunction = ( messages: SessionMessage[] ) => Promise<CompactResult | null>; declare class Session { #private; readonly sessionId: string; /** @internal Constructed by the Sessions capability only. */ constructor( sessionId: string, core: SessionsCore, ready: () => Promise<void> ); /** Register the function `compact()` calls to summarize a branch. */ onCompaction(fn: CompactionFunction): this; /** * Auto-compact after an append once the estimated token count crosses the * threshold. Requires `onCompaction()`. The estimate is derived from the * stamped per-row estimates, never from the transcript. */ compactAfter(tokenThreshold: number): this; /** * Keep an in-memory transcript in step with this session's change feed, * so write sites never hand-patch it. Returns the unsubscribe function. */ mirror< M extends { id: string; } >(options: SessionMirrorOptions<M>): () => void; /** * Stream the active branch path root → leaf (leaf → root with * `newestFirst`) with compaction overlays applied. Peak memory is one * bounded content window, never the whole transcript, and a consumer that * breaks out early leaves the rows it never reached unread. */ history( options?: HistoryReadOptions ): AsyncGenerator<SessionMessage, void, undefined>; /** * Stream history in bounded non-empty batches. Both message count and * serialized bytes bound each batch; a single large message is yielded by * itself. */ historyBatches( options?: HistoryBatchReadOptions ): AsyncGenerator<SessionMessage[], void, undefined>; /** * Materialize the whole selected path. Prefer `history()` or * `getRecentHistory()` inside a Durable Object: this holds every message * of the branch in memory at once. */ getHistory(options?: HistoryReadOptions): Promise<SessionMessage[]>; /** * Byte-budgeted read of the most recent messages on the active branch path * (always at least the leaf). The budget counts each row, its continuation * rows, and the payloads it points at, so it bounds hydrated memory (#1710). */ getRecentHistory( maxContentBytes: number, options?: Pick<HistoryReadOptions, "leafId"> ): Promise<RecentHistoryResult>; /** * Per-row stored sizes (row plus continuation rows and attachments) and * stamped token estimates for the active branch path (root → leaf) * WITHOUT loading message content. */ getHistoryRowStats(leafId?: string | null): Promise<SessionRowStat[]>; getMessage(id: string): Promise<SessionMessage | null>; getLatestLeaf(): Promise<SessionMessage | null>; getBranches(messageId: string): Promise<SessionMessage[]>; /** * Full-text search over this session's text parts. The index is built on * the first call and maintained from then on. */ search( query: string, options?: { limit?: number; } ): Promise<SearchResult[]>; /** * Append one message. Idempotent on id: a repeated append returns the row * already stored and dispatches an `append` event with `inserted: false`. * * A compaction overlay (a `compaction_` id) is derived on read and is never * stored. Clients post their transcript back after every compaction, so * this and every other write drops one silently: nothing is written and no * event is dispatched. */ appendMessage( message: SessionMessage, options?: AppendOptions ): Promise<AppendResult>; /** * Update one stored row. Returns the stored form, or `null` when the id is * not in this session. An unchanged message writes nothing and dispatches * no event. A compaction overlay is never a stored row, so it reports * `null`. */ updateMessage( message: SessionMessage, options?: WriteOptions ): Promise<SessionMessage | null>; /** * @internal Synchronous write aperture for same-isolate first-party * machinery that must commit a message inside a caller-owned SQLite * transaction — the stream cutover, where the finished message and the * discard of its stream rows land together. Bypasses readiness (the * caller owns startup ordering) and defers everything that follows a * write — the change-feed dispatch and auto-compaction: call the returned * `after()` once the transaction commits, or subscribers (the host's * message mirror) never hear about the write. If the transaction rolls * back after an `upsert` ran inside it, call `abandon()`: the write is * gone but the in-memory tail and token-total caches already moved. * Will break without notice; never use from application code. */ __DO_NOT_USE_WILL_BREAK__sync(): { upsert( message: SessionMessage, options?: AppendOptions ): { result: AppendResult; after: () => Promise<void>; }; abandon(): void; }; upsertMessage( message: SessionMessage, options?: AppendOptions ): Promise<AppendResult>; /** * Import one historical message verbatim (migrations, cross-object moves): * explicit parent and timestamp. A row actually written dispatches an * `import` change event so a host cache can mark itself stale; it is not * an `append`, so a cache does not patch itself per imported row, and an * id that already exists writes nothing and dispatches nothing. * * Unlike the other writes, a `compaction_` id is imported as given: a * summary copied from another session's `history()` is the only record of * the context it replaced, and later rows may be parented to it. History * reads hide such a row only when it duplicates one of this session's own * compaction overlays. */ importMessage( message: SessionMessage, options: { parentId: string | null; createdAt: number; } ): Promise<void>; deleteMessages(messageIds: string[]): Promise<void>; clearMessages(): Promise<void>; /** * Store an overlay directly. Dispatches a `compaction` change event: the * rows are untouched, but what a path read returns has changed. */ addCompaction( summary: string, fromMessageId: string, toMessageId: string ): Promise<StoredCompaction>; getCompactions(): Promise<StoredCompaction[]>; /** * Run the registered compaction function and store the result as an * overlay. When `leafId` is given, compact that root-to-leaf branch instead * of the active branch. Requires `onCompaction()`. A compaction function * that throws is reported through the `session:error` capability event and * the call returns `null`. */ compact(leafId?: string | null): Promise<CompactResult | null>; } //#endregion export { CompactOptions as a, isCompactionMessage as c, COMPACTION_PREFIX as i, Session as n, CompactResult as o, SessionMirrorOptions as r, createCompactFunction as s, CompactionFunction as t }; //# sourceMappingURL=handle-zAzh0UW2.d.ts.map