import type { SessionTokenBudgetSummary } from '../../store/budget/index.js'; import type { CostInfo, TokenUsage } from '../common/index.js'; import type { CheckpointId, MessageId, ProjectId, SessionId, TenantId, TurnId } from '../ids/index.js'; import type { Message } from '../message/index.js'; import type { ProviderErrorInfo } from '../provider/index.js'; import type { TurnConfig } from './config.js'; import type { StepResult } from './step.js'; import type { StopReason } from './stop-reason.js'; export type { TurnId }; /** * Where a turn is in its lifecycle. Six members, unchanged from the type it * replaces. `Turn.status` and `TurnSettlement.status` use it. */ export type TurnExecutionStatus = 'idle' | 'pending' | 'running' | 'completed' | 'failed' | 'cancelled'; /** * The domain status a session log's fold derives for a turn. * * - `queued` — the turn exists and has not started. * - `running` — the iteration loop is in flight, or the turn is paused on a * provider wait with no decision open. * - `awaiting_hitl` — synchronously waiting on a human (user present). * - `awaiting_hitl_resolution` — paused with a decision open; the user is * absent and the turn persists until the decision is resolved or the turn * is abandoned. * - `awaiting_subsession` — delegated to a child session and suspended until * it settles. Session-level fan-in treats this as active. * - `succeeded`, `failed`, `cancelled` — terminal. * * The wire form (`WireTurnStatus`) maps both `awaiting_hitl*` members to * `awaiting_input`. */ export type TurnStatus = 'queued' | 'running' | 'awaiting_hitl' | 'awaiting_hitl_resolution' | 'awaiting_subsession' | 'succeeded' | 'failed' | 'cancelled'; /** The durable subset of {@link TurnConfig} recorded in `turn_started.config`. */ export interface TurnConfigSnapshot { model: string; tokenBudget: number; timeoutMs: number; streamIdleTimeoutMs?: number; maxRequestRichContentBytes?: number; maxIterations?: number; temperature?: number; maxResponseTokens?: number; costLimitUsd?: number; } /** * The token ledger a turn spends from. * * Keyed by the ROOT session and the root turn: a root turn opens its own * ledger with its own limit, a child session's turns bind to the key of the * root turn that spawned them, and a resumed paused turn reuses its key. So a * limit that changes between two turns of one session is two ledgers, never a * mismatch. */ export interface TurnBudgetBinding { readonly rootSessionId: SessionId; readonly rootTurnId: TurnId; readonly accountId: string; } /** Which surface opened a session or a turn, and the caller-side ids it used. */ export type OriginProtocol = 'cli' | 'sdk' | 'ag-ui' | 'a2a' | 'acp' | 'http' | 'desktop' | 'resident'; /** What kind of work a turn is. A prompt, a goal round, a resident step and a verification step are each a new turn. */ export type TurnOriginKind = 'prompt' | 'goal-round' | 'resident-step' | 'verification'; export interface Origin { readonly protocol: OriginProtocol; /** The caller's own session, thread or context id. Any string; not required to be a UUID. */ readonly externalSessionId?: string; /** The caller's own id for this unit of work, such as the id an AG-UI client gives its turn. Echoed back verbatim. */ readonly externalTurnId?: string; readonly kind?: TurnOriginKind; readonly goalId?: string; readonly round?: number; } /** * A caller-side name for a session. The index's `external_refs` table is * derived from these (and from `origin`), never written directly, so it * survives a rebuild. */ export interface ExternalRef { readonly protocol: string; readonly kind: 'session' | 'thread' | 'context'; /** Any string; no UUID requirement. */ readonly externalId: string; } /** Which override, if any, decided a turn's `result`. `model` means the model's own text. */ export type TurnResultSource = 'model' | 'guardrail_blocked' | 'guardrail_rewritten' | 'review' | 'outstanding_work' | 'structured_output'; /** How a turn ended: carried on `turn_completed` and `turn_failed`. */ export interface TurnSettlement { /** `completed` or `cancelled` on `turn_completed`; `failed` on `turn_failed`. */ readonly status: TurnExecutionStatus; readonly iterations: number; /** Usage of this turn only; descendant spend is in the budget summary. */ readonly usage: TokenUsage; readonly cost: CostInfo; readonly durationMs: number; /** The assistant message holding the answer, after any `message_replaced`. */ readonly resultMessageId?: MessageId; readonly resultSource: TurnResultSource; readonly structuredOutput?: unknown; /** The provider-chain member that served the end of the turn, when it was not the configured one. */ readonly servingProvider?: string; /** Delegated tasks still running when the turn ended. Not cancelled; named. */ readonly abandonedTaskIds: readonly string[]; /** Background jobs the model was waiting on that were still running. Not stopped; named. */ readonly abandonedJobIds: readonly string[]; } /** Metadata of one turn: who ran it, with what, and where it sits in the session tree. */ export interface TurnMetadata { /** This turn's owner, independent of a shared ancestor token account. */ readonly scope?: { readonly tenantId: TenantId; readonly projectId: ProjectId; readonly sessionId: SessionId; readonly turnId: TurnId; }; agentId: string; agentName: string; config: TurnConfig; /** The provider the turn was configured with: the head of the chain. */ provider: string; /** The chain member the turn was routed to at the end, when not the configured one. */ servingProvider?: string; /** Present on a child session's turn: the parent session that delegated it. */ parentSessionId?: SessionId; /** Present on a child session's turn: the parent turn whose tool call spawned the child. */ parentTurnId?: TurnId; /** Child sessions this turn spawned. */ childSessionIds?: SessionId[]; } /** Where a replayed turn was forked from. A fork is always a NEW session. */ export interface TurnForkOrigin { readonly sessionId: SessionId; readonly turnId: TurnId; readonly checkpointId: CheckpointId; } /** * One turn of a session, as `query()`, `drainQuery()` and `runAgent()` * return it. * * `messages` is the session's context at settle: the fold of the log, with * every `message_replaced` applied. `result` is the authoritative answer, * after guardrail, review, outstanding-work and structured-output overrides. */ export interface Turn { id: TurnId; sessionId: SessionId; status: TurnExecutionStatus; metadata: TurnMetadata; messages: Message[]; /** Usage of this turn only; descendant spend is in `budget`. */ tokenUsage: TokenUsage; budget?: SessionTokenBudgetSummary; budgetBinding?: TurnBudgetBinding; costInfo: CostInfo; currentIteration: number; startedAt: number; endedAt?: number; stopReason?: StopReason; lastError?: string; lastProviderError?: ProviderErrorInfo; result?: string; /** Per-iteration record of what the loop did. Absent on a turn that never entered the loop. */ steps?: readonly StepResult[]; /** Schema-validated final output, when one was requested and produced. */ structuredOutput?: unknown; /** Delegated tasks still running when this turn ended. */ abandonedTaskIds?: readonly string[]; /** Background jobs the model awaited that were still running when this turn ended. */ abandonedJobIds?: readonly string[]; /** Present on a child session's turn. */ parentSessionId?: SessionId; /** Present on a child session's turn. */ parentTurnId?: TurnId; depth?: number; /** Present when this turn's session was forked from another session's checkpoint. */ forkedFrom?: TurnForkOrigin; } /** @see Turn */ export type AgentTurn = Turn; /** * The state of a session's active turn: the last `turn_started` whose * `turnId` has no `turn_completed` or `turn_failed` yet. * * - `paused` — its last segment record is `turn_paused`. Only * `resumeSession` (same `turnId`) or `abandonTurn` ends it. * - `running` — a live lease on the session is held. * - `interrupted` — no live lease and not paused: the process that ran it * is gone. */ export type ActiveTurnState = 'running' | 'paused' | 'interrupted'; /** * A session has at most one active turn. Starting another while one is * running, paused or interrupted is refused with this error. * * Only an `interrupted` turn can be closed automatically, and only when the * caller opts in (`beginTurn({ abandonInterrupted: true })`). A paused turn is * never closed implicitly. Parallel work uses child sessions or separate * sessions. */ export declare class TurnInProgressError extends Error { readonly name: "TurnInProgressError"; readonly sessionId: SessionId; readonly activeTurnId: TurnId; readonly state: ActiveTurnState; constructor(params: { sessionId: SessionId; activeTurnId: TurnId; state: ActiveTurnState; }); } /** * Recognises a {@link TurnInProgressError}, including one from another copy * of this package, so a host protocol server can map it to its own error. */ export declare function isTurnInProgressError(value: unknown): value is TurnInProgressError; //# sourceMappingURL=turn.d.ts.map