/** * The transcript-side rules a turn must apply identically, whoever serves it: * what a client may change about stored history, and how a superseded approval * resolves. * * They live beside the runtime rather than inside a door because more than one * door reads them (the harness runtime here, and the umbrella's thread door in * `@vendoai/vendo`), and a second copy of "may a client rewrite this message?" * is a security answer that could drift. */ import { type ApprovalId } from "@vendoai/core"; import { type UIMessage } from "ai"; export declare function validateMessage(message: UIMessage | undefined): asserts message is UIMessage; export declare function upsertMessage(messages: UIMessage[], message: UIMessage): void; /** AGENT-12: clients may add fresh USER messages and answer approvals — they * may not author assistant content or rewrite history by replaying a known * message id with different parts. */ export declare function validateUpsert(messages: UIMessage[], message: UIMessage): void; export declare function abandonPendingApprovals(messages: UIMessage[]): string[]; /** self-serve P — a new turn never inherits the LAST turn's failure notice. * When the thread's final message is an assistant turn, the ai-SDK CONTINUES * it (handleUIMessageStreamFinish reuses its id and seeds the new turn's state * from its parts), so a retry after a failed turn would append the real answer * UNDER the stale "no model key" line and persist both — the flagship keyless * → `vendo login` → Retry flow, permanently wrong on every reload. Anything * the failed turn actually produced (partial text, tool beats) stays. * * The emptied message is KEPT rather than dropped: persistence writes one row * per changed message and can only add or replace, never remove. A message * dropped here would simply stay in the store — the retry would look clean live * and still reload with the stale notice above the answer. Left in place, the * continuation reuses its id and the write overwrites the stored copy. * * `stored` is the transcript as the STORE holds it, and it is what makes this * work over the wire: the ai-SDK's `regenerate()` slices the assistant message * it is replacing off the history it posts, so the retry arrives ending in the * user message and the record to clear is not in it at all. Carrying the stored * one back on is also what makes the retry a continuation — the SDK reuses that * message's id, so the recovered answer overwrites the failed row instead of * landing under it. Without it the reload showed both, forever. */ export declare function clearFailedTurnRecord(messages: UIMessage[], stored?: readonly UIMessage[]): void; /** AGENT-6: the guard's approval ids for abandoned tool calls. The native tool * part's `approval.id` is the ai-SDK's own handle; the GUARD's approvalId * rides the data-vendo-approval part beside it, keyed by toolCallId — read it * from either the persisted nested envelope or the flat §16 shape. */ export declare function guardApprovalIds(messages: UIMessage[], toolCallIds: string[]): ApprovalId[]; //# sourceMappingURL=transcript-rules.d.ts.map