import { CheckpointWriter, ExecutionNode, NodeId, STREAMING_PLACEHOLDER } from "./checkpoint-types.js"; export type { CheckpointWriter, ExecutionNode, NodeId }; export { STREAMING_PLACEHOLDER }; export declare class CheckpointManager implements CheckpointWriter { private nodes; private orphanedNodes; private _secretValues; private currentNodeChain; private readonly MIN_SECRET_LENGTH; root?: ExecutionNode; checkpointsEnabled: boolean; workflowName?: string; private activeCheckpoint; private pendingUpdate; private version; private org; private apiKey; private apiBaseUrl; private consoleBaseUrl; private printUrl; private runtime?; private runtimeVersion?; private checkpointListener?; private traceId?; private executionRunId?; private replayLookup; get secretValues(): Set; get nodesForTesting(): Map; private callCounters; getNextCallIndex(parentPath: string, componentName: string, props: Record, idPropsKeys: string[] | undefined): number; constructor(opts?: { apiKey?: string; org?: string; disabled?: boolean; apiBaseUrl?: string; consoleBaseUrl?: string; executionRunId?: string; runtime?: "cloud" | "sdk"; runtimeVersion?: string; checkpoint?: ExecutionNode; }); private attachToParent; private handleOrphanedNode; private isNativeFunction; private checkOrphanTimeout; /** * Validates that the execution tree is in a complete state where: * 1. Root node exists * 2. No orphaned nodes are waiting for parents * 3. All parent-child relationships are properly connected */ private isTreeValid; /** * Updates the checkpoint in a non-blocking manner while ensuring consistency. * Special care is taken to: * 1. Queue updates instead of writing immediately to minimize API calls * 2. Only write one checkpoint at a time to maintain order * 3. Track pending updates to ensure no state is lost * 4. Validate tree completeness before writing * * The flow is: * 1. If a write is in progress, mark pendingUpdate = true * 2. When write completes, check pendingUpdate and trigger another write if needed * 3. Only write if tree is valid (has root and no orphans) */ private updateCheckpoint; private havePrintedUrl; private writeCheckpoint; private countSteps; private maskExecutionTree; private isEqual; private withNode; private getEffectiveSecrets; private registerSecrets; private collectSecretValues; private scrubSecrets; private scrubString; private getValueAtPath; private cloneValue; /** * Due to the async nature of component execution, nodes can arrive in any order. * For example, in a tree like: * BlogWriter * └─ OpenAIProvider * └─ Research * * The Research component might execute before OpenAIProvider due to: * - Parallel execution of components * - Different resolution times for promises * - Network delays in API calls * * To handle this, we: * 1. Track orphaned nodes (children with parentIds where parents aren't yet in the graph) because: * - We need to maintain the true hierarchy regardless of arrival order * - We can't write incomplete checkpoints that would show incorrect relationships * - The tree structure is important for debugging and monitoring * * 2. Allow root replacement because: * - The first node to arrive might not be the true root * - We need to maintain correct component hierarchy for visualization * - Checkpoint consumers expect a complete, properly ordered tree * * This approach ensures that even if components resolve out of order, * the final checkpoint will always show the correct logical structure * of the execution. */ addNode(partialNode: Partial & { id: NodeId; }, parentNode?: ExecutionNode, { skipCheckpointUpdate }?: { skipCheckpointUpdate?: boolean; }): ExecutionNode; private addCachedNodeRecursively; completeNode(nodeToUpdate: ExecutionNode, output: unknown, { wrapInPromise }?: { wrapInPromise?: boolean; }): void; addMetadata(nodeToUpdate: ExecutionNode, metadata: Record): void; setWorkflowName(name: string): void; setPrintUrl(printUrl: boolean): void; updateNode(nodeToUpdate: ExecutionNode, updates: Partial): void; write(): void; waitForPendingUpdates(): Promise; private buildReplayLookup; private addToReplayLookup; /** * 1. Check the first node in the list. If it has the same path, content ID and call index use it. * 2. If something does not match, look through the list to find a potential match (and warn about non-deterministic behavior if there is a match): * a. Look for the first node that has the same path, content ID and call index. * b. Look for the first node that has the same path and content ID. * c. Look for the first node that has the same content ID. * d. Look for the first node that has the same component name. * 3. If no match is found, this component is probably not in the checkpoint. If there are nodes in the checkpoint, this indicates non-deterministic behavior. * @param nodeId * @returns */ getNodeFromCheckpoint(nodeId: NodeId): { found: false; node?: ExecutionNode; } | { found: true; node: ExecutionNode; }; slimCheckpoint(checkpoint?: ExecutionNode): any; addCachedSubtreeToCheckpoint(node: ExecutionNode, parent?: ExecutionNode): void; } //# sourceMappingURL=checkpoint.d.ts.map