import { BetaRunnableTool } from "./BetaRunnableTool.js";
import { BetaRunnableToolset } from "./BetaRunnableToolset.js";
import { Anthropic } from "../../index.js";
import { BetaCompactionConfig, BetaMessage, BetaMessageParam, BetaToolUnion, BetaToolUseBlock, MessageCreateParams } from "../../resources/beta.js";
import { BetaMessageStream } from "../BetaMessageStream.js";
import { RequestOptions } from "../../internal/request-options.js";
import type { Simplify } from "../internal/types.js";
/**
 * A ToolRunner handles the automatic conversation loop between the assistant and tools.
 *
 * A ToolRunner is an async iterable that yields either BetaMessage or BetaMessageStream objects
 * depending on the streaming configuration. With `runToolsEagerly` it starts each tool call while the
 * reply is still streaming, unless `deferToolCall()` holds the call.
 */
export declare class BetaToolRunner<Stream extends boolean> {
    #private;
    private client;
    constructor(client: Anthropic, params: BetaToolRunnerParams, options?: BetaToolRunnerRequestOptions);
    [Symbol.asyncIterator](): AsyncIterator<Stream extends true ? BetaMessageStream : Stream extends false ? BetaMessage : BetaMessage | BetaMessageStream>;
    /**
     * Update the parameters for the next API call. This invalidates any cached tool responses. With
     * `runToolsEagerly`, a tool call of the reply that has started doesn't run again.
     *
     * @param paramsOrMutator - Either new parameters or a function to mutate existing parameters
     *
     * @example
     * // Direct parameter update
     * runner.setMessagesParams({
     *   model: 'claude-haiku-4-5',
     *   max_tokens: 500,
     * });
     *
     * @example
     * // Using a mutator function
     * runner.setMessagesParams((params) => ({
     *   ...params,
     *   max_tokens: 100,
     * }));
     */
    setMessagesParams(params: BetaToolRunnerParams): void;
    setMessagesParams(mutator: (prevParams: BetaToolRunnerParams) => BetaToolRunnerParams): void;
    /**
     * Update the request options for future API calls.
     *
     * @param optionsOrMutator - Either new options or a function to mutate existing options
     *
     * @example
     * // Direct options update
     * runner.setRequestOptions({
     *   signal: controller.signal,
     * });
     *
     * @example
     * // Using a mutator function
     * runner.setRequestOptions((prevOptions) => ({
     *   ...prevOptions,
     *   signal: controller.signal,
     * }));
     */
    setRequestOptions(options: BetaToolRunnerRequestOptions): void;
    setRequestOptions(mutator: (prevOptions: BetaToolRunnerRequestOptions) => BetaToolRunnerRequestOptions): void;
    /**
     * Get the tool response for the last message from the assistant.
     * Avoids redundant tool executions by caching results. With `runToolsEagerly`, it reuses the calls of
     * the reply that have started and runs the rest, including the ones `deferToolCall()` is holding, so that no
     * call runs twice.
     *
     * @returns A promise that resolves to a BetaUserMessageParam containing tool results, or null if no tools need to be executed
     *
     * @example
     * const toolResponse = await runner.generateToolResponse();
     * if (toolResponse) {
     *   console.log('Tool results:', toolResponse.content);
     * }
     */
    generateToolResponse(signal?: AbortSignal | null | undefined): Promise<Anthropic.Beta.Messages.BetaUserMessageParam | null>;
    /**
     * Hold a tool call of the current reply until you are done with the reply, which is when it runs without
     * streaming: at the end of the loop body, or when you call `generateToolResponse()`.
     *
     * With `runToolsEagerly` the runner otherwise starts each call while the reply streams, as soon as
     * the model has moved on from it: when the next block starts, or the reply stops with `tool_use`. A call
     * never starts before your stream listeners and any `for await` over the stream have handled that event, so
     * you can call this from either once you have seen the call. The other calls of the reply still start early,
     * except the later calls of the same toolset, which a toolset runs in order.
     * It does nothing for a call that has started, outside the loop body, and without `runToolsEagerly`.
     *
     * @param toolUse - The `tool_use` block of the call, or its id
     *
     * @example
     * for await (const stream of runner) {
     *   stream.on('contentBlock', (block) => {
     *     if (block.type === 'tool_use' && block.name === 'delete_file') {
     *       runner.deferToolCall(block);
     *     }
     *   });
     *   await stream.finalMessage();
     *   // No `delete_file` call has started yet.
     * }
     */
    deferToolCall(toolUse: BetaToolUseBlock | string): void;
    /**
     * The tool calls of the current reply that `deferToolCall()` is holding, in the model's order, as their
     * `tool_use` blocks. A call is in the list once its block has finished streaming, so read the list when you
     * are done with the stream. A call that has started is not in it. It is empty without
     * `runToolsEagerly`.
     *
     * Held calls are listed whatever the reply's `stop_reason`, because `generateToolResponse()` runs them
     * whatever it is. After `max_tokens` the input of the last call can be cut off.
     *
     * @example
     * for await (const stream of runner) {
     *   stream.on('contentBlock', (block) => {
     *     if (block.type === 'tool_use' && block.name === 'delete_file') {
     *       runner.deferToolCall(block);
     *     }
     *   });
     *   await stream.finalMessage();
     *
     *   const held = runner.deferredToolCalls;
     *   if (held.length > 0 && !(await confirm(held))) break;
     * }
     */
    get deferredToolCalls(): BetaToolUseBlock[];
    /**
     * Wait for the async iterator to complete. This works even if the async iterator hasn't yet started, and
     * will wait for an instance to start and go to completion.
     *
     * @returns A promise that resolves to the final BetaMessage when the iterator completes
     *
     * @example
     * // Start consuming the iterator
     * for await (const message of runner) {
     *   console.log('Message:', message.content);
     * }
     *
     * // Meanwhile, wait for completion from another part of the code
     * const finalMessage = await runner.done();
     * console.log('Final response:', finalMessage.content);
     */
    done(): Promise<BetaMessage>;
    /**
     * Returns a promise indicating that the stream is done. Unlike .done(), this will eagerly read the stream:
     * * If the iterator has not been consumed, consume the entire iterator and return the final message from the
     * assistant.
     * * If the iterator has been consumed, waits for it to complete and returns the final message.
     *
     * @returns A promise that resolves to the final BetaMessage from the conversation
     * @throws {AnthropicError} If no messages were processed during the conversation
     *
     * @example
     * const finalMessage = await runner.runUntilDone();
     * console.log('Final response:', finalMessage.content);
     */
    runUntilDone(): Promise<BetaMessage>;
    /**
     * Get the current parameters being used by the ToolRunner.
     *
     * @returns A readonly view of the current ToolRunnerParams
     *
     * @example
     * const currentParams = runner.params;
     * console.log('Current model:', currentParams.model);
     * console.log('Message count:', currentParams.messages.length);
     */
    get params(): Readonly<BetaToolRunnerParams>;
    /**
     * Add one or more messages to the conversation history.
     *
     * @param messages - One or more BetaMessageParam objects to add to the conversation
     *
     * @example
     * runner.pushMessages(
     *   { role: 'user', content: 'Also, what about the weather in NYC?' }
     * );
     *
     * @example
     * // Adding multiple messages
     * runner.pushMessages(
     *   { role: 'user', content: 'What about NYC?' },
     *   { role: 'user', content: 'And Boston?' }
     * );
     */
    pushMessages(...messages: BetaMessageParam[]): void;
    /**
     * Schedule a compaction of the conversation. Once the current turn has finished, including any tool
     * calls, the runner requests a summary and replaces the message history with the compaction response,
     * which is yielded like any other message. Requires the `compact-2026-09-04` beta.
     *
     * @param compaction - The config to send, as `messages.create()` takes it. Defaults to `{ type: 'summarize' }`
     *
     * @example
     * for await (const message of runner) {
     *   if (message.usage.input_tokens > 100_000) {
     *     runner.compactBeforeNextTurn();
     *   }
     * }
     */
    compactBeforeNextTurn(compaction?: BetaCompactionConfig): void;
    /**
     * Give the model more tools without changing `params.tools`, which would miss the prompt cache.
     *
     * Each tool's whole definition is sent in a `tool_addition` block with the next request, and a
     * runnable tool replaces a runnable tool of the same name straight away, even for a call already in
     * the message being handled. A call that started while the reply streamed keeps the old one. A raw definition
     * is only sent: the runner never runs it, and stops running a tool of the same name. Passing a runnable toolset,
     * or a raw definition of a toolset the runner has, throws `ToolsetContractError` and adds nothing: a runner's
     * toolsets come only from `params.tools`. A tool named like one of its toolsets is left to the API, which rejects
     * it with the next request. Requires the `inline-tools-2026-09-15` beta, which the runner does not add for you.
     *
     * @param tools - Runnable tools (for example from `betaZodTool()`) or raw tool definitions
     *
     * @example
     * runner.addTools(queryDatabaseTool);
     */
    addTools(...tools: (BetaRunnableTool<any> | BetaToolUnion)[]): void;
    /**
     * Take tools away from the model without changing `params.tools`, which would miss the prompt cache.
     *
     * The tools stop being run straight away: a call to one of them, even one in the message being
     * handled, gets the same "not found" error result as a call to an unknown tool. A call that started while the
     * reply streamed finishes as usual. The model is told in a `tool_removal` block with the next request. Use
     * {@link addTools} to bring a tool back. Passing the name of one of the runner's toolsets throws
     * `ToolsetContractError` and removes nothing. Requires the `inline-tools-2026-09-15` beta, which the runner does
     * not add for you.
     *
     * @param tools - The tools to remove, or their names
     *
     * @example
     * runner.removeTools('query_database');
     */
    removeTools(...tools: (BetaRunnableTool<any> | string)[]): void;
    /**
     * Makes the ToolRunner directly awaitable, equivalent to calling .runUntilDone()
     * This allows using `await runner` instead of `await runner.runUntilDone()`
     */
    then<TResult1 = BetaMessage, TResult2 = never>(onfulfilled?: ((value: BetaMessage) => TResult1 | PromiseLike<TResult1>) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined | null): Promise<TResult1 | TResult2>;
}
/**
 * Parameters for creating a ToolRunner, extending MessageCreateParams with runnable tools.
 *
 * `compaction` is left out because every request in the loop would compact again; call
 * `BetaToolRunner.compactBeforeNextTurn()` instead.
 */
export type BetaToolRunnerParams = Simplify<Omit<MessageCreateParams, 'tools' | 'compaction'> & {
    tools: (BetaToolUnion | BetaRunnableTool<any> | BetaRunnableToolset)[];
    /**
     * Maximum number of iterations (API requests) to make in the tool execution loop.
     * Each iteration consists of: assistant response → tool execution → tool results.
     * When exceeded, the loop will terminate even if tools are still being requested.
     */
    max_iterations?: number;
    /**
     * Run each tool as soon as its call is complete, before the reply finishes, instead of once you are done
     * with the reply. This is optimistic: if the reply is interrupted or changes course, the tool may have
     * already run, so use `deferToolCall()` to hold the calls that aren't safe to run twice. Requires
     * `stream: true`.
     *
     * A toolset's call, such as a browser or computer action, starts early too when the toolset's earlier calls
     * have ended. Otherwise it waits for the reply, and so do the toolset's later calls. A toolset's `confirm` is
     * still asked before each call runs, so it may be asked while the reply streams.
     *
     * This will be the default in a future version.
     *
     * @default false
     */
    runToolsEagerly?: boolean;
}>;
export type BetaToolRunnerRequestOptions = Pick<RequestOptions, 'headers' | 'signal' | 'fallbackState' | 'openTelemetry'>;
//# sourceMappingURL=BetaToolRunner.d.ts.map