/** * Conversation-shape rules for the OpenAI Chat Completions API. Pure — no * React, no HTTP — so the domain harness can test them. * * What the standards require, and where each rule comes from: * * - Every `tool_calls` entry on an assistant message must be answered by a * `role: "tool"` message carrying the same `tool_call_id`, directly after * that assistant message. Chat Completions rejects the request otherwise * ("An assistant message with 'tool_calls' must be followed by tool messages * responding to each 'tool_call_id'"). LiteLLM only repairs this for * Anthropic, and only with `modify_params` on * (docs.litellm.ai/docs/completion/message_sanitization), so the client owns * it: a turn is only kept in history once it is well-formed. * * - Prompt caching is an exact-prefix match over tools → system → messages. * OpenAI: "Put stable developer instructions and shared reference material * first … place [dynamic content] at the end rather than the beginning" * (developers.openai.com/api/docs/guides/prompt-caching). Anthropic: "For a * prompt with a varying suffix (timestamps, per-request context, the * incoming message), place the breakpoint at the end of the static prefix" * (platform.claude.com/docs/en/docs/build-with-claude/prompt-caching). So * the system prompt carries only the stable part and live state rides in * the current user message, after the history. * * - Anthropic has no `system` role inside `messages` ("there is no 'system' * role for input messages in the Messages API") and "consecutive user or * assistant turns … will be combined into a single turn" * (platform.claude.com/docs/en/api/messages); LiteLLM merges consecutive * same-role messages for it. A mid-conversation note is therefore a `user` * message, never a `system` one, and two user messages in a row are fine. */ export interface ConversationToolCall { id: string; [key: string]: unknown; } export interface ConversationMessage { role: string; content: string | null; tool_calls?: ConversationToolCall[]; tool_call_id?: string; [key: string]: unknown; } /** One exchange: the user's message and everything the model did in reply. */ export type Turn = ConversationMessage[]; export declare const CONTEXT_OPEN = ""; export declare const CONTEXT_CLOSE = ""; /** Appended to the system prompt whenever a context block is in use. */ export declare const CONTEXT_PREAMBLE = "A user message may begin with a block: the live state of the application at the moment that message was sent. It is authoritative and more current than anything said in earlier turns."; /** The user's text, prefixed with the live context block when there is one. */ export declare const withContext: (text: string, context: string) => string; /** * The messages array for one request: stable system prompt, the kept turns * verbatim, then the incoming message carrying the per-request context. */ export declare const buildRequestMessages: (systemPrompt: string, history: readonly Turn[], userText: string, context: string) => ConversationMessage[]; /** * Keeps the newest `max` turns. Whole turns only, so an assistant `tool_calls` * message is never separated from the tool messages that answer it. */ export declare const trimTurns: (turns: readonly Turn[], max: number) => { turns: Turn[]; dropped: number; }; /** Tool calls in `turn` that no tool message answers. */ export declare const unansweredToolCalls: (turn: readonly ConversationMessage[]) => ConversationToolCall[]; /** * Makes `turn` valid to resend by inserting a tool message for every * unanswered tool call, directly after the assistant message that made it. * `result(call)` supplies the content (JSON-stringified). Mutates `turn`; * returns the messages it inserted. */ export declare const answerUnansweredToolCalls: (turn: ConversationMessage[], result: (call: ConversationToolCall) => unknown) => ConversationMessage[]; //# sourceMappingURL=conversation.d.ts.map