import type { ModelMessage, TextStreamPart, ToolSet, TypedToolResult } from "ai"; type ToolResponsePart = Extract["content"][number]; type InlineToolResultPart = Extract; import type { AssistantStepFinishReason, RuntimeIdentity } from "#protocol/message.js"; import type { RunMode } from "#shared/run-mode.js"; import type { JsonObject } from "#shared/json.js"; import type { HarnessEmitFn, HarnessSession, SessionStateMap, StepInput } from "#harness/types.js"; /** * Tracks emission lifecycle state across harness step invocations. * * Persisted on `session.state` so the state survives when the durable * workflow runtime recreates the harness at each `"use step"` boundary. */ export interface HarnessEmissionState { readonly sessionStarted: boolean; readonly sequence: number; readonly stepIndex: number; readonly turnId: string; } /** Reads the emission state, returning defaults when absent. */ export declare function getHarnessEmissionState(state: SessionStateMap | undefined): HarnessEmissionState; /** * Returns `true` when the harness is **between turns** — either no turn * has started yet (initial state) or the previous turn has emitted its * epilogue (or recoverable failure cascade) and reset. * * Returns `false` while a turn is in progress, including during * tool-loop continuations and runtime-action resumes within the same * turn. Callers that gate per-turn work (eg. lifecycle hook dispatch) * use this predicate to distinguish a fresh delivery from a * continuation of an in-flight turn. * * Implemented over the empty-`turnId` sentinel that `emitTurnEpilogue` * and `emitRecoverableFailedTurn` write — clients should never read * `state.turnId` directly to make this distinction. */ export declare function isHarnessBetweenTurns(session: HarnessSession): boolean; /** * Writes the emission state onto a new copy of the session. */ export declare function setHarnessEmissionState(session: HarnessSession, state: HarnessEmissionState): HarnessSession; /** * Emits `session.started` (once), `turn.started`, and `message.received` at the * beginning of a new turn. Returns updated emission state. */ export declare function emitTurnPreamble(emitFn: HarnessEmitFn, input: StepInput, state: HarnessEmissionState, runtimeIdentity?: RuntimeIdentity): Promise; /** * Emits `step.started` for one model call. */ export declare function emitStepStarted(emitFn: HarnessEmitFn, state: HarnessEmissionState, messages?: readonly import("ai").ModelMessage[]): Promise; interface FailedStepPayload { readonly code: string; readonly details?: JsonObject; readonly message: string; } /** * Emits the full terminal failure cascade: `step.failed` → * `turn.failed` → `session.failed`. * * Use this when the session cannot be salvaged (structural config * error, auth misconfig, non-recoverable provider response). The * `session.failed` tail tells adapters the session is dead and no * further follow-up is possible on the same continuation token. */ export declare function emitFailedStep(emitFn: HarnessEmitFn, state: HarnessEmissionState, input: FailedStepPayload & { readonly sessionId: string; }): Promise; /** * Emits the recoverable failure cascade: `step.failed` → * `turn.failed` → `session.waiting`. */ export declare function emitRecoverableFailedTurn(emitFn: HarnessEmitFn, state: HarnessEmissionState, input: FailedStepPayload): Promise; /** * Returns updated emission state for the next step in the current turn. */ export declare function advanceStep(state: HarnessEmissionState): HarnessEmissionState; /** * Emits `turn.completed` and either `session.waiting` or `session.completed`. * Returns updated emission state with an incremented sequence. */ export declare function emitTurnEpilogue(emitFn: HarnessEmitFn, state: HarnessEmissionState, mode: RunMode): Promise; /** * Maps an AI SDK finish reason string to the eve-owned * {@link AssistantStepFinishReason} union. Unknown values become `"other"`. */ export declare function normalizeAssistantStepFinishReason(value: string | undefined): AssistantStepFinishReason; /** * Result of consuming one step's `fullStream`. * * `handledInlineToolResultCallIds` lists approval-resume tool-result * call ids the stream already handled inline — either emitted as * `action.result` events or routed to the authorization park path. * `emitStepActions` skips these to avoid double-emission. * * `inlineToolResultParts` holds the same tool-results in * `ToolResultPart` shape. The AI SDK omits them from * `stepResult.response.messages` on the approval-resume path, so the * harness splices them into persisted history to keep the prior turn's * `tool_use` block balanced with a matching `tool_result` on replay. * * `inlineAuthorizationResults` holds approval-resume tool-results whose * output is an {@link AuthorizationSignal}. These are surfaced into * `stepResult.toolResults` for the park detector instead of being emitted * as plain `action.result` events. */ interface EmittedStreamContent { readonly handledInlineToolResultCallIds: ReadonlySet; readonly inlineAuthorizationResults: readonly TypedToolResult[]; readonly inlineToolResultParts: readonly InlineToolResultPart[]; } /** * Consumes the AI SDK `fullStream` and emits real-time text and reasoning * events. * * `tool-result` parts that have no preceding `tool-call` in this stream * are emitted inline as `action.result` events. This is the * approval-resume path: when a previously-parked tool call is approved, * the AI SDK enqueues the executed tool-result onto the same step's * stream before the next LLM call. Emitting `action.result` inline keeps * it ahead of the message events that depend on it. * * Tool-call, tool-approval-request, and non-resumed tool-result events * are still emitted by `emitStepActions` from the `onStepFinish` * callback so the existing single-step batch ordering is preserved. */ export declare function emitStreamContent(emitFn: HarnessEmitFn, state: HarnessEmissionState, fullStream: AsyncIterable>): Promise; export {};