import { C as ChatMessagePart } from '../parts-DIKcC1p6.js';
export { a as ChatAttachmentKind, b as ChatAttachmentPart, c as ChatFilePart, d as ChatImagePart, e as ChatInteractionPart, f as ChatMentionKind, g as ChatMentionPart, h as ChatNoticePart, i as ChatPartTime, j as ChatPlanPart, k as ChatReasoningPart, l as ChatStepFinishPart, m as ChatStepStartPart, n as ChatSubtaskPart, o as ChatTextPart, p as ChatToolPart, q as ChatToolState, r as ChatToolStatus, s as ChatUsageTokens, t as ChatWorkProductPart, D as DEFAULT_ATTACHMENT_PROMPT_HEADER, S as StorableHarnessPartKind, u as attachmentInputToPart, v as attachmentKindForMime, w as attachmentPartsFromMessageParts, x as buildAttachmentPromptBlock, y as historyContentWithAttachments, z as isChatAttachmentPart, A as isChatInteractionPart, B as isChatMentionPart, E as isChatPlanPart, F as isChatStepFinishPart, G as isChatTextPart, H as isChatToolPart, I as isChatWorkProductPart, J as mentionInputToPart, K as mentionPartsFromMessageParts, L as toChatMessageParts } from '../parts-DIKcC1p6.js';
import * as drizzle_orm from 'drizzle-orm';
import * as drizzle_orm_sqlite_core from 'drizzle-orm/sqlite-core';
import { SQLiteColumnBuilderBase, AnySQLiteTable, AnySQLiteColumn, BaseSQLiteDatabase } from 'drizzle-orm/sqlite-core';
export { a as attachmentPartKey } from '../stream-normalizer-DnuqkZvw.js';
import '@tangle-network/agent-interface';
import '../contract-CEewO6DI.js';
import '../types-DeEOhQbv.js';
import '../plans/index.js';

/**
 * Pure (drizzle-free) pieces of the chat store: thread-title derivation, the
 * bulk-delete bound, and the typed input error. Split from `./schema`/`./store`
 * so the root barrel can re-export them without dragging the optional
 * drizzle-orm peer into every root-entry consumer.
 */
/** Bounds a single bulk-delete request's write set; product surfaces cap
 *  thread lists at far fewer, so a larger batch is a malformed or hostile
 *  request. (Lifted from legal's api.threads.bulk-delete route.) */
declare const BULK_DELETE_MAX_THREADS = 200;
/** Invalid caller input (missing/oversized ids, empty title). Products map it
 *  to a 400; anything else out of the store is a real failure. */
declare class ChatStoreInputError extends Error {
    constructor(message: string);
}
/** Thread titles come from the first message — keep the list scannable by
 *  storing only its first non-empty line, capped at 80 chars, never the whole
 *  multi-page prompt. (Lifted verbatim from legal's chat.new route.) */
declare function threadTitleFromMessage(message: string): string;

/** A product table referenced by FK — only the `id` column is touched. */
type ChatParentTable = AnySQLiteTable & {
    id: AnySQLiteColumn;
};
/** Define options to customize chat thread and message table creation including workspace and naming prefixes */
interface CreateChatTablesOptions<TThreadExtras extends Record<string, SQLiteColumnBuilderBase> = {}, TMessageExtras extends Record<string, SQLiteColumnBuilderBase> = {}> {
    /** The product's workspace table — threads reference `workspaceTable.id`
     *  with cascade. Omitted: `workspace_id` stays a plain indexed text column
     *  (products whose tenant table lives in another database). */
    workspaceTable?: ChatParentTable;
    /** Prefixes table AND index names (`'chat_'` → `chat_thread`,
     *  `idx_chat_thread_workspace`) for products that namespace chat tables in a
     *  shared database. Default: unprefixed `thread`/`message` (legal/gtm row
     *  compatibility). */
    tablePrefix?: string;
    /** Product columns merged into the thread table (the `/missions` extras
     *  pattern) — e.g. a `status` lifecycle enum or gtm's scope columns. */
    threadExtraColumns?: TThreadExtras;
    /** Product columns merged into the message table — e.g. legal's
     *  `vault_files`. */
    messageExtraColumns?: TMessageExtras;
}
/** Build chat-related SQLite tables with customizable thread and message columns */
declare function createChatTables<TThreadExtras extends Record<string, SQLiteColumnBuilderBase> = {}, TMessageExtras extends Record<string, SQLiteColumnBuilderBase> = {}>(options?: CreateChatTablesOptions<TThreadExtras, TMessageExtras>): {
    threads: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
        name: `${string}thread`;
        schema: undefined;
        columns: {
            id: drizzle_orm.HasDefault<drizzle_orm.IsPrimaryKey<drizzle_orm.NotNull<drizzle_orm_sqlite_core.SQLiteTextBuilderInitial<"id", [string, ...string[]], number | undefined>>>>;
            workspaceId: drizzle_orm.NotNull<drizzle_orm_sqlite_core.SQLiteTextBuilderInitial<"workspace_id", [string, ...string[]], number | undefined>>;
            title: drizzle_orm.NotNull<drizzle_orm_sqlite_core.SQLiteTextBuilderInitial<"title", [string, ...string[]], number | undefined>>;
            category: drizzle_orm_sqlite_core.SQLiteTextBuilderInitial<"category", [string, ...string[]], number | undefined>;
            isPinned: drizzle_orm.HasDefault<drizzle_orm.NotNull<drizzle_orm_sqlite_core.SQLiteBooleanBuilderInitial<"is_pinned">>>;
            createdAt: drizzle_orm.HasDefault<drizzle_orm.NotNull<drizzle_orm_sqlite_core.SQLiteTimestampBuilderInitial<"created_at">>>;
            updatedAt: drizzle_orm.HasDefault<drizzle_orm.NotNull<drizzle_orm_sqlite_core.SQLiteTimestampBuilderInitial<"updated_at">>>;
        } & TThreadExtras extends infer T extends Record<string, drizzle_orm.ColumnBuilderBase<drizzle_orm.ColumnBuilderBaseConfig<drizzle_orm.ColumnDataType, string>, object>> ? { [Key in keyof T]: drizzle_orm.BuildColumn<TTableName, {
            _: Omit<T[Key]["_"], "name"> & {
                name: T[Key]["_"]["name"] extends "" ? drizzle_orm.Assume<Key, string> : T[Key]["_"]["name"];
            };
        }, TDialect>; } : never;
        dialect: "sqlite";
    }>;
    messages: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
        name: `${string}message`;
        schema: undefined;
        columns: {
            id: drizzle_orm.HasDefault<drizzle_orm.IsPrimaryKey<drizzle_orm.NotNull<drizzle_orm_sqlite_core.SQLiteTextBuilderInitial<"id", [string, ...string[]], number | undefined>>>>;
            threadId: drizzle_orm.NotNull<drizzle_orm_sqlite_core.SQLiteTextBuilderInitial<"thread_id", [string, ...string[]], number | undefined>>;
            role: drizzle_orm.NotNull<drizzle_orm_sqlite_core.SQLiteTextBuilderInitial<"role", ["user", "assistant", "system", "tool"], number | undefined>>;
            content: drizzle_orm.NotNull<drizzle_orm_sqlite_core.SQLiteTextBuilderInitial<"content", [string, ...string[]], number | undefined>>;
            parts: drizzle_orm.HasDefault<drizzle_orm.$Type<drizzle_orm_sqlite_core.SQLiteTextJsonBuilderInitial<"parts">, ChatMessagePart[]>>;
            toolName: drizzle_orm_sqlite_core.SQLiteTextBuilderInitial<"tool_name", [string, ...string[]], number | undefined>;
            model: drizzle_orm_sqlite_core.SQLiteTextBuilderInitial<"model", [string, ...string[]], number | undefined>;
            inputTokens: drizzle_orm_sqlite_core.SQLiteIntegerBuilderInitial<"input_tokens">;
            outputTokens: drizzle_orm_sqlite_core.SQLiteIntegerBuilderInitial<"output_tokens">;
            reasoningTokens: drizzle_orm_sqlite_core.SQLiteIntegerBuilderInitial<"reasoning_tokens">;
            cacheReadTokens: drizzle_orm_sqlite_core.SQLiteIntegerBuilderInitial<"cache_read_tokens">;
            cacheWriteTokens: drizzle_orm_sqlite_core.SQLiteIntegerBuilderInitial<"cache_write_tokens">;
            costUsd: drizzle_orm_sqlite_core.SQLiteRealBuilderInitial<"cost_usd">;
            createdAt: drizzle_orm.HasDefault<drizzle_orm.NotNull<drizzle_orm_sqlite_core.SQLiteTimestampBuilderInitial<"created_at">>>;
        } & TMessageExtras extends infer T_1 extends Record<string, drizzle_orm.ColumnBuilderBase<drizzle_orm.ColumnBuilderBaseConfig<drizzle_orm.ColumnDataType, string>, object>> ? { [Key_1 in keyof T_1]: drizzle_orm.BuildColumn<TTableName, {
            _: Omit<T_1[Key_1]["_"], "name"> & {
                name: T_1[Key_1]["_"]["name"] extends "" ? drizzle_orm.Assume<Key_1, string> : T_1[Key_1]["_"]["name"];
            };
        }, TDialect>; } : never;
        dialect: "sqlite";
    }>;
};
/**
 * The base (no-extras) table pair, pinned via an instantiation expression:
 * `ReturnType<typeof createChatTables>` on the bare generic substitutes the
 * extras params with their CONSTRAINT (`Record<string,
 * SQLiteColumnBuilderBase>`), stamping an index signature into the column map
 * that widens every concrete column to `unknown`/`notNull: false` — concrete
 * factory results then fail `extends ChatTables`. (`teams`' `createTeamTables`
 * is non-generic, so its plain `ReturnType` never hits this.)
 */
type ChatTables = ReturnType<typeof createChatTables<{}, {}>>;
/** Resolve the selected fields of a chat thread row from the chat threads table */
type ChatThreadRow = ChatTables['threads']['$inferSelect'];
/** Resolve the selected structure of a chat message row from the messages table */
type ChatMessageRow = ChatTables['messages']['$inferSelect'];
/** Resolve the type for inserting a new chat thread row into the threads table */
type NewChatThreadRow = ChatTables['threads']['$inferInsert'];
/** Resolve the type for inserting a new chat message row into the messages table */
type NewChatMessageRow = ChatTables['messages']['$inferInsert'];

/**
 * Typed CRUD over the tables from `createChatTables`. Works against any
 * SQLite drizzle driver (D1, libsql, better-sqlite3) — builders are awaited,
 * never `.run()`/`.all()`, so sync and async drivers behave identically.
 *
 * Access control is an injected seam, never an import: single-thread routes
 * check workspace access themselves (they know the thread), while
 * `bulkDeleteThreads` REQUIRES an `assertAccess` callback because one request
 * can span workspaces — it is called once per distinct workspace and any
 * throw rejects the whole request before a single delete runs (fail-closed;
 * legal's bulk-delete semantics).
 *
 * Deletes run messages-first in ONE `db.batch` round trip when the driver has
 * one (D1, libsql), so a partial failure never leaves orphaned rows behind a
 * deleted thread; drivers without `batch` (better-sqlite3) fall back to
 * sequential awaits in the same order.
 */

/** Any SQLite drizzle database — `any` erases the driver-specific run-result
 *  and schema generics so better-sqlite3, D1, and libsql handles all fit.
 *  `batch` is structural: present on D1/libsql drizzle instances. */
type ChatDatabase = BaseSQLiteDatabase<'sync' | 'async', any, any> & {
    batch?: (statements: [unknown, ...unknown[]]) => Promise<unknown[]>;
};
/** Product-injected access check. Throw to deny; the store never interprets
 *  users or roles itself. */
type WorkspaceAccessCheck = (workspaceId: string) => void | Promise<void>;
/** Define input parameters for listing threads within a workspace with pagination options */
interface ListThreadsInput {
    workspaceId: string;
    /** Clamped to 1..200; default 50 (legal's list route semantics). */
    limit?: number;
    /** Clamped to >= 0; default 0. */
    offset?: number;
}
/** Represent a paginated collection of chat threads with total count and pagination details */
interface ListThreadsResult<TThread = ChatThreadRow> {
    threads: TThread[];
    total: number;
    limit: number;
    offset: number;
}
/** Define input parameters required to create a new thread in a workspace */
interface CreateThreadInput {
    workspaceId: string;
    /** Title source when `title` is absent: first non-empty line, 80-char cap
     *  (`threadTitleFromMessage`). */
    firstMessage?: string;
    /** Explicit title; still normalized through `threadTitleFromMessage` so a
     *  multi-page paste never becomes a sidebar entry. */
    title?: string;
    category?: string | null;
    isPinned?: boolean;
    /** Opaque product-column values written verbatim in the SAME insert (the
     *  `/missions` extras pattern). Never read, validated, or defaulted here. */
    extras?: Record<string, unknown>;
}
/** Define input parameters for appending a message to a chat thread with optional metadata */
interface AppendMessageInput {
    /** Caller-assigned primary key. Omitted, the column default assigns a random
     *  hex id (today's behavior). Incremental assistant persistence passes a
     *  DETERMINISTIC id derived from the turn's own identity, so a re-entered
     *  turn (crashed worker, durable-driver retry) finds and updates the row a
     *  previous attempt started instead of inserting a second one. */
    id?: string;
    threadId: string;
    role: 'user' | 'assistant' | 'system' | 'tool';
    content: string;
    parts?: ChatMessagePart[];
    toolName?: string | null;
    model?: string | null;
    inputTokens?: number | null;
    outputTokens?: number | null;
    reasoningTokens?: number | null;
    cacheReadTokens?: number | null;
    cacheWriteTokens?: number | null;
    costUsd?: number | null;
    /** Opaque product-column values written verbatim in the SAME insert. */
    extras?: Record<string, unknown>;
}
/** Fields an existing message row may be patched with. Every field is
 *  optional and only DEFINED fields are written, so a partial patch never
 *  clears a column it does not mention. `threadId` and `role` are absent on
 *  purpose: a message never moves thread or changes speaker.
 *
 *  Exists for incremental assistant persistence — the streaming turn writes
 *  the row once and then patches it as content accumulates, so the durable
 *  transcript is at most one cadence interval behind the live stream. */
interface UpdateMessageInput {
    content?: string;
    parts?: ChatMessagePart[];
    toolName?: string | null;
    model?: string | null;
    inputTokens?: number | null;
    outputTokens?: number | null;
    reasoningTokens?: number | null;
    cacheReadTokens?: number | null;
    cacheWriteTokens?: number | null;
    costUsd?: number | null;
    /** Opaque product-column values written verbatim in the SAME update. */
    extras?: Record<string, unknown>;
}
/** Define options to configure message listing with optional limit and offset parameters */
interface ListMessagesOptions {
    limit?: number;
    offset?: number;
}
/** Define input for bulk deleting threads with access checks per workspace */
interface BulkDeleteThreadsInput {
    ids: string[];
    /** Called once per distinct workspace the ids touch, before ANY delete. */
    assertAccess: WorkspaceAccessCheck;
}
/** Manage chat threads and messages with operations for listing, creating, updating, and deleting data */
interface ChatStore<TThread = ChatThreadRow, TMessage = ChatMessageRow> {
    listThreads(input: ListThreadsInput): Promise<ListThreadsResult<TThread>>;
    getThread(threadId: string): Promise<TThread | null>;
    createThread(input: CreateThreadInput): Promise<TThread>;
    renameThread(threadId: string, title: string): Promise<TThread | null>;
    pinThread(threadId: string, isPinned: boolean): Promise<TThread | null>;
    /** Messages + thread in one batch. Resolves false when the thread does not
     *  exist. `assertAccess` (optional) receives the thread's workspaceId before
     *  the delete — single-thread callers usually check access themselves. */
    deleteThread(threadId: string, options?: {
        assertAccess?: WorkspaceAccessCheck;
    }): Promise<boolean>;
    bulkDeleteThreads(input: BulkDeleteThreadsInput): Promise<{
        deleted: number;
    }>;
    /** Ordered oldest-first: `created_at`, then rowid (insertion order within a
     *  same-second burst — a user+assistant pair lands in one epoch second). */
    listMessages(threadId: string, options?: ListMessagesOptions): Promise<TMessage[]>;
    /** Inserts the message and bumps the thread's `updatedAt` in one batch so
     *  workspace recency sorts stay truthful. */
    appendMessage(input: AppendMessageInput): Promise<TMessage>;
    /** Patches an existing message and bumps its thread's `updatedAt` in the
     *  same batch. Resolves `null` when the id does not exist. Only defined
     *  patch fields are written. */
    updateMessage(id: string, patch: UpdateMessageInput): Promise<TMessage | null>;
    /** Removes one message. Resolves false when the id does not exist. Used by
     *  incremental persistence to retract a draft row for a turn that ended
     *  producing nothing, so an empty assistant row is never left behind. */
    deleteMessage(id: string): Promise<boolean>;
}
/** Create a chat store managing threads and messages based on the provided database and tables */
declare function createChatStore<TTables extends ChatTables>(db: ChatDatabase, tables: TTables): ChatStore<TTables['threads']['$inferSelect'], TTables['messages']['$inferSelect']>;

export { type AppendMessageInput, BULK_DELETE_MAX_THREADS, type BulkDeleteThreadsInput, type ChatDatabase, ChatMessagePart, type ChatMessageRow, type ChatParentTable, type ChatStore, ChatStoreInputError, type ChatTables, type ChatThreadRow, type CreateChatTablesOptions, type CreateThreadInput, type ListMessagesOptions, type ListThreadsInput, type ListThreadsResult, type NewChatMessageRow, type NewChatThreadRow, type UpdateMessageInput, type WorkspaceAccessCheck, createChatStore, createChatTables, threadTitleFromMessage };
