import type { AssistantMessageEvent, ImageContent, Message, Model, SimpleStreamOptions, streamSimple, TextContent, ThinkingContent, Tool, ToolCall, ToolResultMessage, UserMessage } from "../ml/index.js";
import type { Static, TSchema } from "@sinclair/typebox";
/** Streaming entry point; may resolve synchronously or via a Promise when config is fetched async. */
export type StreamFn = (...args: Parameters<typeof streamSimple>) => ReturnType<typeof streamSimple> | Promise<ReturnType<typeof streamSimple>>;
/**
 * Reasoning effort tier requested from models that expose one.
 * Heads up: the top "xhigh" tier is currently only honored by a few OpenAI
 * frontier models; most providers cap out at "high".
 */
export type ThinkingLevel = "off" | "minimal" | "low" | "medium" | "high" | "xhigh";
/**
 * Open extension point for application-defined message kinds.
 * Downstream code adds its own kinds by merging this module's interface:
 *
 * @example
 * ```typescript
 * declare module "./types.js" {
 *   interface CustomAgentMessages {
 *     reminder: ReminderMessage;
 *     statusBanner: StatusBannerMessage;
 *   }
 * }
 * ```
 */
export interface CustomAgentMessages {
}
/**
 * AgentMessage: every base LLM message plus any app-registered custom kinds.
 * The indirection lets applications introduce their own message kinds without
 * giving up type safety against the underlying LLM message shapes.
 */
export type AgentMessage = Message | CustomAgentMessages[keyof CustomAgentMessages];
export type AgentToolUpdateCallback<T = any> = (partialResult: AgentToolResult<T>) => void;
export interface AgentToolResult<T> {
    content: (TextContent | ImageContent)[];
    details: T;
    isError?: boolean;
}
export interface AgentTool<TParameters extends TSchema = TSchema, TDetails = any> extends Tool<TParameters> {
    label: string;
    /**
     * Marks a tool that only inspects state and never mutates it (read/ls/grep/
     * find/websearch/webfetch/todoread). Hosts can lean on this to auto-allow
     * such tools in a permission policy without re-deriving the read-only set by
     * name. Optional and defaults to undefined → treated as "not known read-only".
     */
    readOnly?: boolean;
    execute: (toolCallId: string, params: Static<TParameters>, signal?: AbortSignal, onUpdate?: AgentToolUpdateCallback<TDetails>) => Promise<AgentToolResult<TDetails>>;
}
/**
 * The verdict a {@link CanUseToolFn} returns for a single tool call.
 *
 * - `allow` proceeds with execution; an optional `updatedInput` replaces the
 *   validated arguments before the tool runs (e.g. a sanitized command).
 * - `deny` short-circuits: the tool never executes and `message` is surfaced as
 *   an `isError` tool result so the model sees why it was blocked.
 */
export type PermissionDecision = {
    behavior: "allow";
    updatedInput?: unknown;
} | {
    behavior: "deny";
    message: string;
};
/**
 * Hard permission gate consulted immediately before a tool executes. Hosts
 * supply it to enforce an allow/ask/deny policy; the loop awaits it (passing the
 * abort signal so a pending prompt can be cancelled) and acts on the verdict.
 *
 * Entirely optional — when omitted the loop allows every tool, preserving
 * today's behavior.
 */
export type CanUseToolFn = (toolName: string, input: unknown, opts: {
    signal?: AbortSignal;
}) => Promise<PermissionDecision>;
export interface AgentContext {
    systemPrompt: string;
    messages: AgentMessage[];
    tools?: AgentTool<any>[];
}
/**
 * The agent's full runtime state: configuration plus live conversation data.
 */
export interface AgentState {
    systemPrompt: string;
    model: Model<any>;
    thinkingLevel: ThinkingLevel;
    tools: AgentTool<any>[];
    messages: AgentMessage[];
    isStreaming: boolean;
    streamMessage: AgentMessage | null;
    pendingToolCalls: Set<string>;
    error?: string;
}
/**
 * Settings that drive a single agent loop run.
 */
export interface AgentLoopConfig extends SimpleStreamOptions {
    model: Model<any>;
    /**
     * Maps the AgentMessage[] down to a model-ready Message[] ahead of every model call.
     *
     * Every AgentMessage has to become a UserMessage, AssistantMessage, or
     * ToolResultMessage. Anything the model shouldn't see (UI-only notices,
     * status entries, and so on) is simply dropped here.
     *
     * @example
     * ```typescript
     * const flatten = (history: AgentMessage[]): Message[] =>
     *   history.flatMap((entry) => {
     *     // A bespoke kind gets restated as ordinary user text.
     *     if (entry.role === "todo") {
     *       return [{ role: "user", content: entry.content, timestamp: entry.timestamp }];
     *     }
     *     // Purely visual entries are withheld from the model.
     *     if (entry.role === "diagnostic") {
     *       return [];
     *     }
     *     // Everything else is already model-shaped, so pass it straight through.
     *     return [entry];
     *   });
     * ```
     */
    convertToLlm: (messages: AgentMessage[]) => Message[] | Promise<Message[]>;
    /**
     * Optional hook that reshapes the context while it is still AgentMessages,
     * i.e. before `convertToLlm` runs.
     *
     * Good fit for work that has to happen at the AgentMessage layer:
     * - keeping the context window in check (trimming older entries)
     * - pulling in extra context from elsewhere
     *
     * @example
     * ```typescript
     * const reshape = async (history: AgentMessage[]): Promise<AgentMessage[]> => {
     *   const spent = await tallyTokens(history);
     *   if (spent <= windowLimit) {
     *     return history;
     *   }
     *   return trimFromFront(history, windowLimit);
     * };
     * ```
     */
    transformContext?: (messages: AgentMessage[], signal?: AbortSignal) => Promise<AgentMessage[]>;
    /**
     * Supplies a fresh API key per model call.
     *
     * Handy when the credential is a short-lived OAuth token that can lapse
     * while a slow stretch of tool calls is still running.
     */
    getApiKey?: (provider: string) => Promise<string | undefined> | string | undefined;
    /**
     * Hard permission gate consulted right before each tool executes. When set,
     * the loop awaits it with the tool name and its VALIDATED arguments; a `deny`
     * verdict short-circuits to an `isError` tool result (the tool never runs),
     * while an `allow` verdict proceeds — substituting `updatedInput` when given.
     *
     * Omit it to allow every tool, i.e. exactly today's behavior.
     */
    canUseTool?: CanUseToolFn;
    /**
     * Yields steering messages to splice into the run while it is in flight.
     *
     * Consulted after each tool finishes to pick up user interruptions. When it
     * hands back messages, any still-pending tool calls are abandoned and those
     * messages join the context before the next model call.
     *
     * This is the channel for nudging the agent mid-task.
     */
    getSteeringMessages?: () => Promise<AgentMessage[]>;
    /**
     * Yields follow-up messages to handle once the agent is otherwise done.
     *
     * Consulted when there are no remaining tool calls and no steering input.
     * Returning messages appends them and pushes the agent into another turn.
     *
     * Use it for input that should wait until the current work wraps up.
     */
    getFollowUpMessages?: () => Promise<AgentMessage[]>;
    /**
     * Names of tools that are safe to run concurrently because they only read
     * (never mutate) state. Consecutive runs of such calls within one assistant
     * turn are dispatched in parallel (bounded by {@link maxToolConcurrency});
     * everything else still runs one-at-a-time in request order.
     *
     * When omitted the loop falls back to a conservative built-in set
     * (`read`/`ls`/`grep`/`find`/`websearch`/`webfetch`/`todoread`). Tools that
     * aren't on the list — including dynamic/MCP/composio tools — always run
     * serially, preserving today's behavior.
     */
    readOnlyToolNames?: ReadonlySet<string>;
    /**
     * Upper bound on how many read-only tool calls run at once. Defaults to the
     * `CLAUDE_CODE_MAX_TOOL_USE_CONCURRENCY` / `INDUS_MAX_TOOL_CONCURRENCY`
     * environment override, or 10. Set to 1 to force fully-sequential dispatch.
     */
    maxToolConcurrency?: number;
}
type AgentLifecycleEvent = {
    type: "agent_start";
} | {
    type: "agent_end";
    messages: AgentMessage[];
};
type TurnEvent = {
    type: "turn_start";
} | {
    type: "turn_end";
    message: AgentMessage;
    toolResults: ToolResultMessage[];
};
type MessageEvent = {
    type: "message_start";
    message: AgentMessage;
} | {
    type: "message_update";
    message: AgentMessage;
    assistantMessageEvent: AssistantMessageEvent;
} | {
    type: "message_end";
    message: AgentMessage;
};
type ToolExecutionEvent = {
    type: "tool_execution_start";
    toolCallId: string;
    toolName: string;
    args: any;
} | {
    type: "tool_execution_update";
    toolCallId: string;
    toolName: string;
    args: any;
    partialResult: any;
} | {
    type: "tool_execution_end";
    toolCallId: string;
    toolName: string;
    result: any;
    isError: boolean;
};
/**
 * The events the Agent streams out so a UI can stay in sync.
 * They report granular lifecycle progress across messages, turns, and tool runs.
 */
export type AgentEvent = AgentLifecycleEvent | TurnEvent | MessageEvent | ToolExecutionEvent;
/** Grouping of the event-type strings, handy for filtering or logging. */
export declare const AGENT_EVENT_GROUPS: {
    readonly agent: readonly ["agent_start", "agent_end"];
    readonly turn: readonly ["turn_start", "turn_end"];
    readonly message: readonly ["message_start", "message_update", "message_end"];
    readonly toolExecution: readonly ["tool_execution_start", "tool_execution_update", "tool_execution_end"];
};
export type AgentEventType = AgentEvent["type"];
export type ExtractAgentEvent<TType extends AgentEventType> = Extract<AgentEvent, {
    type: TType;
}>;
/**
 * Decide at runtime whether a value matches one of the recognized AI message shapes.
 */
export declare function validateMessage(value: unknown): value is Message;
/** Narrows a value to a user message. */
export declare function isUserMessage(value: AgentMessage | unknown): value is UserMessage;
/** Narrows a value to a thinking block carried inside an assistant message. */
export declare function isThinking(value: unknown): value is ThinkingContent;
/** Narrows a value to a tool-call block carried inside an assistant message. */
export declare function isToolCall(value: unknown): value is ToolCall;
export {};
