maybeSnapshot method

Future<String?> maybeSnapshot({
  1. String? status,
  2. AgentErrorDetails? error,
  3. String? snapshotId,
  4. AgentFinishReason? finishReason,
})

Evaluates whether to save a snapshot to the persistent store.

Implementation

Future<String?> maybeSnapshot({
  String? status,
  AgentErrorDetails? error,
  String? snapshotId,
  AgentFinishReason? finishReason,
}) async {
  if (_store == null ||
      (isDetached && snapshotId != _lastSnapshot?.snapshotId)) {
    return _lastSnapshot?.snapshotId;
  }

  final currentVersion = session.getVersion();
  if (currentVersion == _lastSnapshotVersion && status == null) {
    return _lastSnapshot?.snapshotId;
  }

  final currentState = session.getState();
  final effectiveId = snapshotId ?? newSnapshotId;

  // When an id is reused (e.g. the detached `pending` snapshot is upgraded to
  // `completed` under the same id), `_lastSnapshot` already points at that id.
  // Inherit its parent instead of pointing the snapshot at itself, which would
  // create a self-referential `parentId` and later trip the cycle guard in
  // `loadChat`/`getSnapshot`.
  final reusingId =
      effectiveId != null && effectiveId == _lastSnapshot?.snapshotId;
  final parentId = reusingId
      ? _lastSnapshot?.parentId
      : _lastSnapshot?.snapshotId;

  // The `invocationEnd` write (the only caller that omits a status) persists
  // as `completed` so it stays a valid resume target.
  final now = DateTime.now().toUtc().toIso8601String();
  final snapshotInput = SessionSnapshot(
    snapshotId: effectiveId ?? '',
    sessionId: session.sessionId,
    createdAt: _lastSnapshot?.createdAt ?? now,
    updatedAt: now,

    // Stamp an initial heartbeat on a `pending` (detached, in-flight)
    // snapshot. A background heartbeat loop refreshes it; if it goes stale
    // the snapshot is reported as `expired` on read (worker presumed dead).
    heartbeatAt: status == 'pending' ? now : null,
    state: currentState,
    parentId: parentId,
    status: SnapshotStatus(status ?? 'completed'),
    finishReason: finishReason,
    error: error != null ? _toErrorInfo(error) : null,
  );

  final assignedId = await _store.saveSnapshot(
    effectiveId,
    _abortAwareMutator(snapshotInput),
    context: context,
  );
  if (assignedId == null) {
    // Snapshot was aborted concurrently; preserve the existing ID.
    return effectiveId;
  }

  snapshotInput.snapshotId = assignedId;
  _lastSnapshot = snapshotInput;
  _lastSnapshotVersion = currentVersion;

  return assignedId;
}