import { RemoteError, type RemoteErrorDetail } from '../errors.js'; import type { AiInvocationTransitionRecord, AiToolEffectTransitionRecord } from '../ai/invocation.js'; import type { AiBudgetEstimate } from '../ai/budget.js'; export declare class ProtocolNegotiationError extends Error { constructor(message: string); } /** The server terminally rejected a mutating frame (DurableAck.errors). */ export declare class FrameRejectedError extends RemoteError { /** Stable server code, e.g. "InvalidTaskToken", "NonDeterminism", "StoreError". */ readonly seq: number; readonly attemptedDelivery?: any; readonly legacyCode: string; constructor(seq: number, legacyCode: string, message: string, attemptedDelivery?: any, structured?: RemoteErrorDetail); } /** The session stream ended/errored while frames were in flight. Transient: retry on the next session. */ export declare class SessionClosedError extends Error { readonly cause?: unknown; constructor(message: string, cause?: unknown); } /** Local safety bound reached before another acknowledged frame could be queued. */ export declare class SessionBackpressureError extends SessionClosedError { constructor(limit: number); } export interface SessionConnectOptions { /** Maximum mutation/capacity frames awaiting a server acknowledgement. */ maxPendingAcks?: number; /** Maximum time to wait for hello_ack before tearing down the stream. */ helloTimeoutMs?: number; /** Explicit opt-in for the frozen pre-negotiation N-1 server ACK. */ allowLegacyServer?: boolean; } export interface SessionHelloParams { namespace: string; taskQueue: string; identity: string; buildId: string; maxConcurrentWorkflows: number; maxConcurrentActivities: number; /** Interval at which the worker will Ping while holding in-flight tasks. */ pingIntervalMs: number; sdkVersion: string; sandboxAttestation?: import('../types.js').SandboxAttestation; } /** hello_ack payload (proto SessionHelloAck), field-normalized. */ export interface SessionHelloAck { sessionId: string; /** Grace the server applies after a disconnect before reaping in-flight workflow tasks. */ reapGraceMs: number; serverVersion: string; selectedProtocolMajor: number; selectedProtocolMinor: number; selectedCapabilities: string[]; selectedPayloadCodecVersion: number; selectedEnvelopeVersion: number; /** P6.3 SQL-contract handshake, folded into session setup. */ sqlContract?: { store_kind: string; contract_version: number; postgres_target_fingerprint: string; }; } export interface CapacityState { appliedSeq: number; workflowLimit: number; workflowInFlight: number; activityLimit: number; activityInFlight: number; draining: boolean; } export interface SessionEvents { /** A WorkflowTask push — identical payload to the old poll stream. */ onWorkflowTask: (task: any) => void; /** An ActivityTask push. */ onActivityTask: (task: any) => void; /** CancelNotice for a run this worker holds a task for. */ onCancel: (notice: { namespace: string; workflow_id: string; run_id: string; }) => void; /** The server is evicting this worker (e.g. stale build_id); the stream closes after this. */ onEvicted: (reason: string) => void; /** An operator requested graceful drain for this exact server session. */ onDrainRequest: (request: { request_id: string; reason: string; }) => void; } /** Minimal duplex-stream surface consumed by SessionClient (mockable in tests). */ export interface DuplexLike { write(frame: any, cb?: (err?: Error | null) => void): boolean; end(): void; cancel?(): void; on(event: 'data' | 'error' | 'end' | 'status', listener: (arg?: any) => void): unknown; on(event: 'drain', listener: () => void): unknown; } export declare class SessionClient { private readonly maxPendingAcks; private readonly helloTimeoutMs; private readonly allowLegacyServer; private stream; private events; private seq; private pending; private pendingCapacity; private closedFlag; private legacyPeer; private writeBackpressured; private helloWaiter; private helloTimer; private closeResolve; /** Resolves when the stream ends (with the terminal error, if any). */ readonly closed: Promise; constructor(stream: DuplexLike, events: SessionEvents, maxPendingAcks?: number, helloTimeoutMs?: number, allowLegacyServer?: boolean); /** * Open a session over an already-constructed WorkerSession gRPC client: * sends hello (seq 1, first — proto invariant 4) and resolves with the * hello_ack. Rejects on any transport/protocol error before the ack. */ static connect(client: any, hello: SessionHelloParams, events: SessionEvents, options?: SessionConnectOptions): { session: SessionClient; ack: Promise; }; get isClosed(): boolean; get supportsDynamicCredits(): boolean; get supportsDeliveryIdentity(): boolean; private hello; /** Send a workflow-task completion; resolves after the server's DurableAck (Law 2). */ completeWorkflowTask(request: any): Promise; /** Send an activity completion; resolves after the server's DurableAck (Law 2). */ completeActivity(request: any): Promise; /** * P9.3 eager flush: persist implicit-step effect records mid-slice. * Resolves only after the server acked the WHOLE frame durably. */ recordEffects(taskToken: string, records: any[], deliveryIdentity: any): Promise; appendOutputChunk(taskToken: string, deliveryIdentity: any, input: { streamName: string; offset: number; chunk: Uint8Array; contentType: string; idempotencyKey: string; endMarker: boolean; errorType?: string; errorMessage?: string; }): Promise; recordAiInvocation(taskToken: string, deliveryIdentity: any, record: AiInvocationTransitionRecord, transitionEventId: string, transitionIdempotencyKey: string): Promise; recordAiToolEffect(taskToken: string, deliveryIdentity: any, record: AiToolEffectTransitionRecord, transitionEventId: string, transitionIdempotencyKey: string): Promise; reserveAiBudget(taskToken: string, deliveryIdentity: any, reservationId: string, idempotencyKey: string, estimate: AiBudgetEstimate, createdAt: Date, transitionEventId: string, transitionIdempotencyKey: string): Promise; settleAiBudget(taskToken: string, deliveryIdentity: any, reservationId: string, invocationId: string, settledAt: Date, transitionEventId: string, transitionIdempotencyKey: string): Promise; settleRecoveredAiBudget(taskToken: string, deliveryIdentity: any, input: { recoveryId: string; reservationId: string; invocationId: string; toolCallId: string; evidenceSha256: string; settledAt: Date; }): Promise; resolveAiBudget(taskToken: string, deliveryIdentity: any, reservationId: string, evidence: 'provider_call_not_started' | 'outcome_unknown', evidenceSha256: string, resolvedAt: Date, transitionEventId: string, transitionIdempotencyKey: string): Promise; /** * Lease renewal + liveness (replaces the unary Heartbeat / the P7.1 * workflow-task keepalive). Fire-and-forget: pings carry no ack; * cancellation flows back as a CancelNotice frame. */ ping(tasks: Array<{ task_token: string; delivery_identity: any; }>): void; /** Apply absolute execution limits, or stop all new delivery while draining. */ updateAvailability(maxConcurrentWorkflows: number, maxConcurrentActivities: number, draining?: boolean): Promise; /** Return a delivered task that local execution never started. */ releaseTask(taskToken: string, reason: string, deliveryIdentity: any): Promise; /** * Best-effort activity output chunk (P3.5) — nothing durable, nothing * acked. The returned promise reflects only the local write flush, so * ActivityContextImpl can log a transport failure once. */ streamChunk(taskToken: string, chunk: Uint8Array, chunkSeq: number, deliveryIdentity: any): Promise; /** Half-close politely; the server tears the session down and reaps after grace. */ close(): void; /** Cancel immediately and settle local waiters even if the peer never responds. */ abort(reason: string): void; private sendAwaited; private onFrame; private onClosed; private pendingLimitError; private trackWrite; }