import type { NodeKeyPair } from '@forgezero/runtime/identity'; import { type AgentHeartbeatAck } from '@forgezero/runtime/agent-observation'; import { type AgentRelease } from './agent-update'; import { type AgentUpdateReceipt, type AgentUpdateResponse } from './agent-update-helper'; import type { AgentOperationTelemetry } from './telemetry-runtime'; import type { AgentRuntimeHandoff } from './agent-handover'; import type { PlatformSecretAuthorityDirective, PlatformSecretAuthorityReceipt } from './platform-secret-authority'; export interface AgentObservation { version: string; os: { id: string; versionId: string; }; architecture: string; mode: 'attested' | 'enrolled'; runtimeCapabilities?: { native: true; ociRunc: boolean; kataQemuSnp: boolean; }; /** Signed host evidence. Placement still reserves declared capacity; it never chases transient utilization. */ capacity?: { logicalCpu: number; memoryMiB: number; storageGiB: number; }; utilization?: { load1mMilli: number; memoryUsedMiB: number; storageUsedGiB: number; }; update?: AgentUpdateReceipt; deploymentIntake?: { generation: number; state: 'running' | 'paused'; appliedAtTs: number; }; /** * Runner-only evidence that the signed process has constructed the metal * admission pull and that its server/attestation claim gate is open now. * It is capability evidence, not a browser- or caller-controlled request. */ bootstrapIntake?: { configured: boolean; claimsEnabled: boolean; }; platformSecretAuthority?: PlatformSecretAuthorityReceipt; } export interface AgentHeartbeatResponse { ok: true; nodeKey: string; intervalSeconds: number; workClaimsEnabled?: boolean; desiredAgentRelease?: AgentRelease; desiredAgentUpdate?: { attemptId: string; leaseExpiresAtTs: number; release: AgentRelease; }; deploymentIntake?: { generation: number; state: 'running' | 'paused'; }; desiredPlatformSecretAuthority?: PlatformSecretAuthorityDirective; } export interface AgentHostMetrics { logicalCpu: number; memoryBytes: number; memoryFreeBytes: number; storageBytes: number; storageFreeBytes: number; load1m: number; } export interface AgentHeartbeatOptions { apiUrl: string; nodeKey: string; keys: NodeKeyPair; mode: AgentObservation['mode']; updateTarget?: 'compute' | 'metal'; version?: string; fetch?: (input: URL, init: RequestInit) => Promise; requestTimeoutMs?: number; observation?: () => AgentObservation; /** Last applied server-owned deployment-intake generation, reported on the next heartbeat. */ deploymentIntakeObservation?: () => AgentObservation['deploymentIntake']; /** Current local readiness of the signed metal-admission pull. */ bootstrapIntakeObservation?: () => AgentObservation['bootstrapIntake']; platformSecretAuthorityObservation?: () => PlatformSecretAuthorityReceipt | undefined; applyPlatformSecretAuthority?: (directive: PlatformSecretAuthorityDirective) => Promise; /** Apply the authenticated desired state before any new deployment claim is allowed. */ applyDeploymentIntake?: (directive: NonNullable) => Promise | void; /** Server lifecycle gate for deployment, migration and delegated bootstrap claims. */ applyWorkClaims?: (enabled: boolean) => Promise | void; receiptPath?: string; now?: () => number; /** Stop new lifecycle/deploy claims and await current jobs after candidate readiness. */ prepareUpdate?: (release: AgentRelease) => Promise; /** Exact post-drain Vault cursor and fenced leases sent only through the root update helper. */ handoffState?: () => AgentRuntimeHandoff; /** Recover only after a prepared candidate could not be committed. */ recoverUpdate?: (cause: unknown) => Promise | void; applyUpdate?: (phase: 'prepare' | 'commit' | 'abort', release: AgentRelease, currentVersion: string, attemptId: string) => Promise; setTimer?: (callback: () => void, ms: number) => unknown; clearTimer?: (handle: unknown) => void; onEvent?: (event: string, detail?: unknown) => void; /** Only a sealed, schema-validated ACK for this exact node can signal availability. */ onAccepted?: (ack: AgentHeartbeatAck) => void; telemetry?: AgentOperationTelemetry; } export declare function observeAgentHost(version?: string, mode?: AgentObservation['mode'], osRelease?: string, architecture?: NodeJS.Architecture, metrics?: AgentHostMetrics): AgentObservation; /** One PQ-authenticated observation and optional supervised update decision. */ export declare function heartbeatAgentOnce(options: AgentHeartbeatOptions): Promise; /** Server-paced heartbeat; stopping waits for the active PQ request/update handoff. */ export declare function startAgentHeartbeat(options: AgentHeartbeatOptions): { stop(): Promise; readonly active: boolean; };