/** * Compatibility port of upstream pi-ai's transcript-replay helpers for legacy * extensions importing the aliased package roots (`@earendil-works/pi-ai`, * `@mariozechner/pi-ai`). * * Upstream pi-ai 1.x exposes a transcript-replay module * (`src/utils/transcript.ts`, present since at least 1.0.2) and re-exports it * from the package root (`normalizeContext`, `getCurrentSystemMessage`, * `getCurrentTools`, `resolveTranscriptTools`, …). OMP forked before that * module existed and has no equivalent anywhere in `@oh-my-pi/pi-ai`, so the * star re-export in `legacy-pi-ai-shim.ts` cannot satisfy these imports and * legacy extensions fail Bun's static named-export check (observed with * `pi-optchat` importing `getCurrentSystemMessage`). * * The logic below is ported verbatim from upstream `pi-ai` 1.1.0 * (`src/utils/transcript.ts` + the `contentText`/`getSystemMessageText` helpers * from `src/utils/text.ts`). Types are structural: the compat layer must not * depend on OMP's exact `SystemMessage`/`Tool` drift, and legacy callers pass * plain message arrays (upstream's own `TranscriptMessages` is `readonly {role}[]`). */ /** A message-like entry; replay helpers only read entries whose role is `"system"`. */ interface TranscriptMessageLike { role: string; content?: unknown; timestamp?: number; sections?: Record | undefined; toolsAdded?: TranscriptToolLike[] | undefined; toolsRemoved?: TranscriptToolReferenceLike[] | undefined; } /** A tool-like declaration as carried by system-message tool state. */ interface TranscriptToolLike { name: string; description?: string; parameters: unknown; constrainedSampling?: boolean | undefined; } /** Upstream `ToolReference`: a by-name removal marker. */ interface TranscriptToolReferenceLike { name: string; } /** Extract and join text from message content (upstream `text.ts`). */ export declare function contentText(content: unknown, separator?: string): string; /** Render a system message as a complete prompt: its content followed by its sections. */ export declare function getSystemMessageText(message: TranscriptMessageLike): string; /** Upstream `TranscriptContext`: a context whose system prompt and tools are folded into messages. */ export interface TranscriptContext { messages: TranscriptMessageLike[]; } /** Build the leading system message for a prompt and tool set. Returns undefined when both are empty, so an empty transcript stays empty. */ export declare function createInitialSystemMessage(systemPrompt: string | undefined, tools: TranscriptToolLike[] | undefined): TranscriptMessageLike | undefined; /** * Fold `Context.systemPrompt` and `Context.tools` into a leading system message. * This is the only entry point that produces a {@link TranscriptContext}; every * provider-facing function expects the result. */ export declare function normalizeContext(context: { systemPrompt?: string | undefined; tools?: TranscriptToolLike[] | undefined; messages: TranscriptMessageLike[]; }): TranscriptContext; /** Return the leading system message, if the transcript starts with one. */ export declare function getInitialSystemMessage(messages: readonly TranscriptMessageLike[]): TranscriptMessageLike | undefined; /** Drop the leading system message for APIs that carry the prompt outside the message list. */ export declare function withoutInitialSystemMessage(messages: readonly T[]): T[]; /** Resolve the tools available after applying every transcript delta in order. */ export declare function getCurrentTools(messages: readonly TranscriptMessageLike[]): TranscriptToolLike[]; /** * Replay every system message into one leading system message holding the current * prompt and tools. Later `content` is appended to the base prompt, `sections` are * patched by name, and tools are resolved with {@link getCurrentTools}. */ export declare function getCurrentSystemMessage(messages: readonly TranscriptMessageLike[]): TranscriptMessageLike | undefined; /** Render the current system prompt text after replaying every system message. */ export declare function getCurrentSystemPrompt(messages: readonly TranscriptMessageLike[]): string; /** Rebuild the transcript for APIs without mid-conversation system messages: the replayed system message leads, and every later system message is dropped. */ export declare function collapseSystemMessages(context: TranscriptContext): TranscriptContext; /** Keep later system messages in place when the model accepts them; otherwise collapse them. */ export declare function resolveTranscript(context: TranscriptContext, supportsMidConvoSystemMessages: boolean | undefined): TranscriptContext; /** Strip executable and display-only fields from a tool before transcript comparison or persistence. */ export declare function toToolDeclaration(tool: TranscriptToolLike): Record; /** * Whether two tools declare the same interface to the model. * * Both sides go through {@link toToolDeclaration} first: its JSON round-trip drops the * typebox symbol keys and `undefined` fields that a structural comparison would see, and * builds both objects with the same key order, so comparing the serialized declarations * is exact. This avoids a deep-equal dependency in a browser-safe package. */ export declare function declarationsEqual(left: TranscriptToolLike, right: TranscriptToolLike): boolean; export interface TranscriptToolStateChanges { toolsAdded: Record[]; toolsRemoved: TranscriptToolReferenceLike[]; } /** Compare two complete tool states. A changed definition is a removal followed by an addition. */ export declare function getToolStateChanges(previous: readonly TranscriptToolLike[], current: readonly TranscriptToolLike[]): TranscriptToolStateChanges; /** Every definition referenced by transcript tool state, in first-declaration order. */ export declare function getDeclaredTools(messages: readonly TranscriptMessageLike[]): TranscriptToolLike[]; /** * Whether a tool name was declared twice with different definitions. A transport that * can only reference previously declared tools by name cannot replay such a history. * * External compatibility requirement: upstream pi-ai 1.1.0 marks this function * `@deprecated` but keeps it exported for legacy API consumers, and this compat * layer must reproduce upstream's public surface 1:1 for legacy extensions that * import it by name. Removal follows upstream's removal, not ours. */ export declare function hasToolRedefinitions(messages: readonly TranscriptMessageLike[]): boolean; /** Whether tool history contains a removal or same-name redeclaration that an addition-only transport cannot replay. */ export declare function hasNonAdditiveToolChanges(messages: readonly TranscriptMessageLike[]): boolean; export interface TranscriptTools { /** Tools sent in the top-level request field. */ requestTools: TranscriptToolLike[]; /** * Whether later system messages carry their own `toolsAdded` as in-place additions. * When false, `requestTools` already holds the complete current tool set. */ anchorsAdditions: boolean; } /** * Split tool declarations between the top-level request field and in-place additions. * Transports that can anchor additions at a system message keep the initial tools at the * top and load later ones where they appear; that only works when no tool was removed or * redeclared, so everything else sends the current tool list. */ export declare function resolveTranscriptTools(messages: readonly TranscriptMessageLike[], supportsToolAdditions: boolean): TranscriptTools; export {};