import type { GenerateTextOnStepStartCallback, ModelMessage, PrepareStepFunction, ProviderMetadata, StepResult, ToolSet } from "ai"; import type { TurnPosition } from "#harness/session-machine/view.js"; import type { ModelProfile } from "#harness/model-profile.js"; import { type HarnessEmitFn, type HarnessSession, type HarnessToolLookup } from "#harness/types.js"; /** * The subset of `StepResult` that the harness reads after a step completes, captured by the * `onStepEnd` callback. */ export type HarnessStepResult = Pick, "content" | "finishReason" | "providerMetadata" | "response" | "text" | "toolCalls" | "toolResults" | "usage"> & { readonly invalidInputToolCallIds?: ReadonlySet; }; /** * Input for {@link buildStepHooks}. */ interface StepHooksInput { readonly auth?: import("#channel/types.js").SessionAuthContext | null; readonly profile: ModelProfile; /** * Starts the model step the SDK is about to run. Omitted when the step already started, as * it has for a retry of the same step. */ readonly startStep?: (messages: readonly ModelMessage[]) => Promise; readonly session: HarnessSession; } /** * Composable hooks returned by {@link buildStepHooks}. */ interface StepHooks { /** * `ToolLoopAgent` `onStepStart` callback. * * Starts the step from the prepared step input. */ readonly onStepStart: GenerateTextOnStepStartCallback; /** * `ToolLoopAgent` `onStepEnd` callback. * * Emits `actions.requested`, `action.result`, and `step.completed` events * from the captured step result. */ readonly onStepEnd: (step: StepResult) => Promise; /** * `ToolLoopAgent` `prepareStep` callback. * * Handles cache/provider metadata. Compaction happens in the tool-loop * before `agent.stream()`. */ readonly prepareStep: PrepareStepFunction; /** * Promise that resolves when `onStepEnd` has completed. * * Await this after consuming the stream to ensure all step events * have been emitted before proceeding to post-step handling. * * Resolves once per hooks instance: a retried model call must rebuild * hooks via a fresh `ModelCaller.call` attempt. Re-running a call against * hooks whose `stepResult` already resolved reads the previous attempt's * result, not the retry's. * * Never settles when the step does not finish — e.g. the AI SDK's * incomplete-stream rejection (`NoOutputGeneratedError`) skips * `onStepEnd` entirely. Consumers must surface stream errors as * throws before awaiting this promise (`emitStreamContent` does), or * the await hangs. */ readonly stepResult: Promise; } /** * Builds composable `onStepStart`, `prepareStep`, and `onStepEnd` closures that * own all step-internal work: emission, compaction, and prompt caching. * * The harness passes these hooks to `ToolLoopAgent` and reads the * results via `stepResult` after the agent finishes. */ export declare function buildStepHooks(input: StepHooksInput): StepHooks; /** * Emits `actions.requested`, `action.result`, and `step.completed` events * from a captured step result. * * Tool calls and results that match `excludedActionToolNames`, belong to * tool-approval requests, or are marked `invalid` by the AI SDK (e.g. the * model emitted unparsable JSON) are filtered out of the emitted events. * The AI SDK feeds the invalid-call error back to the model on the next * step via `step.response.messages` so it can retry with well-formed * arguments — the runtime event stream only sees successfully parsed * tool calls. * * `handledInlineToolResultCallIds` contains results emitted by * `emitStreamContent` or sent to authorization. Skip them here. */ export declare function emitStepActions(emitFn: HarnessEmitFn, state: TurnPosition, step: HarnessStepResult, options: { readonly emittedActionCallIds?: ReadonlySet; readonly excludedActionCallIds?: ReadonlySet; readonly excludedActionToolNames: ReadonlySet; readonly handledInlineToolResultCallIds?: ReadonlySet; readonly tools: HarnessToolLookup; }): Promise; export declare function readGatewayGenerationId(providerMetadata: ProviderMetadata | undefined): string | undefined; export {};