/** * Make a loaded conversation history safe to replay against any provider by * enforcing the tool-call / tool-result invariant in BOTH directions. * * Anthropic's Messages API requires every `tool_use` block to be followed by * `tool_result` blocks for all of its ids. OpenAI-compatible providers * (DeepSeek, OpenRouter, Azure) are stricter still: a `role:'tool'` message * must immediately follow the `assistant` + `tool_calls` that declared its id, * and an unanswered `tool_calls` is equally rejected, surfacing as * `400 Messages with role 'tool' must be a response to a preceding message * with 'tool_calls'`. A conversation interrupted mid-turn (a crash after the * assistant message persisted but before all tool results landed; a client * failure that never replayed the results) leaves a malformed graph in the * store, and replaying it 400s. * * {@link sanitizeConversation} walks the messages in order: * * - **Complete tool turn** (every declared id has a matching result in the * immediately-following tool run) is kept, with the results re-emitted in * `toolCalls` order, exactly one per call. Any extra / duplicate / orphan * tool message interleaved in that run is dropped. * - **Dangling tool turn** (one or more declared ids unanswered) has its * assistant `toolCalls` stripped; the text `content` is preserved as a * plain assistant message (an empty one is dropped entirely); the partial * tool results are dropped. * - **Orphan tool result** (a `role:'tool'` message whose parent assistant * is missing or was dropped as dangling) is dropped. Replaying it trips * the 400 above on OpenAI-compatible providers and a BadRequestError on * Anthropic. * * Unlike the wire-level normalizer the provider adapters apply (which * SYNTHESIZES stub results so an in-flight request stays well-formed), the * load boundary DROPS incomplete turns: an interrupted turn is abandoned * history, and a fake "result missing" message would pollute the model's * future context. * * Pure and idempotent: safe to apply at any load boundary, and re-running over * an already-sanitized array is a no-op. {@link OrmConversationStore} applies * it in `load()` so persisted histories are replay-safe by default. */ import type { AiMessage } from './types.js'; export declare function sanitizeConversation(messages: AiMessage[]): AiMessage[]; //# sourceMappingURL=sanitize-conversation.d.ts.map