navigateSessionTree function

Future<String?> navigateSessionTree(
  1. Session session,
  2. String? targetId, {
  3. required SummarizeFn summarize,
  4. int tokenBudget = 0,
  5. String? customInstructions,
  6. bool? fromHook,
  7. CancelToken? cancelToken,
})

Navigate session to targetId (omp's tree navigation with branch summarization): the branch being left is summarized via summarize into a branch_summary record prepended to the context of the branch being entered, and the active leaf moves. Returns the new branch_summary record id, or null when no summary was written (no-op navigation, nothing to summarize, or summarization failed/aborted).

This is the wiring point for tree navigation: hosts that expose branch switching call this instead of Session.moveTo directly. Summarization failure never blocks navigation — the abandoned branch stays in the tree regardless; the summary is a convenience projection, not the only copy.

Implementation

Future<String?> navigateSessionTree(
  Session session,
  String? targetId, {
  required SummarizeFn summarize,
  int tokenBudget = 0,
  String? customInstructions,
  bool? fromHook,
  CancelToken? cancelToken,
}) async {
  final oldLeafId = await session.getLeafId();
  if (oldLeafId == targetId) return null;

  String? summary;
  Object? details;
  if (oldLeafId != null && targetId != null) {
    final collected = await collectEntriesForBranchSummary(
      session,
      oldLeafId,
      targetId,
    );
    if (collected.entries.isNotEmpty) {
      final result = await generateBranchSummary(
        collected.entries,
        summarize: summarize,
        tokenBudget: tokenBudget,
        customInstructions: customInstructions,
        cancelToken: cancelToken,
      );
      if (result.aborted) return null;
      if (result.summary != null) {
        summary = result.summary;
        details = {
          'readFiles': result.readFiles ?? const <String>[],
          'modifiedFiles': result.modifiedFiles ?? const <String>[],
        };
      }
    }
  }
  return session.moveTo(
    targetId,
    summary: summary,
    details: details,
    fromHook: fromHook,
  );
}