/** * Shared Giellie types (server + client). Message blocks follow the * Anthropic content-block shape but are kept loose (`Block`) because * MiniMax also returns `thinking` blocks that must round-trip untouched. */ export type Block = { type: string; [key: string]: unknown }; /** Synthetic tool_result text when a tool_use has no recorded result. */ export const RESULT_UNAVAILABLE_TEXT = "Result unavailable — this action may or may not have executed. Verify the current state (read the record) before retrying."; export interface StoredMessage { role: "user" | "assistant"; content: Block[]; ts: string; } export interface PendingToolUse { id: string; /** Dotted MCP name, e.g. `orders.update`. */ name: string; input: Record; /** Sends, cancels/merges and contact-detail changes — the trust toggle never auto-approves these. */ confirmAlways: boolean; /** Why this always asks (badge text). Absent on rows saved before it existed. */ confirmReason?: string; } export interface PendingAction { tool_uses: PendingToolUse[]; /** tool_result blocks already produced this turn (read tools). */ completed: Block[]; /** Every tool_use id of the assistant turn, in original order. */ order: string[]; } /** * Identifies which pending approval a decision is for. Client and server * compare it so a stale tab cannot approve a newer, different request. */ export function pendingFingerprint(p: PendingAction): string { return p.order.join(","); } export interface GielieChatSummary { id: string; title: string; updated: string; } export interface GielieChat extends GielieChatSummary { messages: StoredMessage[]; pending_action: PendingAction | null; attachments: string[]; }