Skip to main content

Module tool_fold

Module tool_fold 

Source
Expand description

TCF: fold sources for the *ai:opencode* conversation buffer.

Two [lattice_core::FoldSource]s, both reading the same single-pass layout (project_conversation) so a fold’s line range can never drift from the rendered text:

  • ToolCallFoldSource — one fold per tool call that has captured input/output detail, spanning its ▸ summary [status] head line through the last detail row.
  • ReasoningFoldSource — one fold per multi-line reasoning block.

Both fold closed: true by default (a fresh tool call / reasoning block opens collapsed; za on the head line expands it). Lattice fold semantics keep the head line visible (start_line < line <= end_line, see lattice_host::folds::FoldIndex::line_inside_closed_fold), so a closed fold shows only the summary and elides the detail rows at the cell layer — a collapsed transcript costs the renderer nothing per hidden line (paramount #1).

Mode-owned, exactly the shape diff-mode uses for [HunkFoldSource]: AiConversationMode::on_activate constructs one of each (holding a ConversationStore clone) and registers them via the FoldOverlayService; the mode’s Drop guard removes them. Each holds the store, so compute_folds reads the currently-published conversation on every recompute — no FoldContext, no buffer round-trip.

[HunkFoldSource]: crate — see lattice_diff::fold::HunkFoldSource for the precedent this mirrors.

§Identity — the streaming-coherence fix

A closed fold’s expansion state is carried across recomputes by [lattice_core::Fold::identity], not by its line range. The transcript grows above a tool call on every streamed token, shifting its line range; keying identity on the tool-call id (not the range) is what keeps an expanded call expanded as content lands above it. Reasoning blocks carry no wire id, so their identity is keyed on the block’s ordinal in document order — stable because earlier turns are never rewritten, so a given reasoning block stays the nth one as it streams.

Structs§

ConversationFold
TCF: one foldable region in the projected transcript, produced by project_conversation. start_line is the fold head (stays visible when closed); start_line + 1 ..= end_line are the rows that hide. identity carries closed-state across streaming recomputes.
ReasoningFoldSource
TCF: folds each multi-line reasoning block (closed by default).
ToolCallFoldSource
TCF: folds each tool call’s captured detail rows (closed by default).

Enums§

ConversationFoldKind
TCF: which kind of block a ConversationFold covers, so each [FoldSource] can filter project_conversation’s span list to its own.

Constants§

REASONING_FOLD_NAMESPACE
Namespace for the per-buffer reasoning fold provider id. See TOOL_FOLD_NAMESPACE.
TOOL_FOLD_NAMESPACE
Namespace for the per-buffer tool-call fold provider id. OR’d with the buffer’s id (low 32 bits) so the source is distinct in the registry — FoldOverlayService::add_source keys removal on the id. Distinct high bits from REASONING_FOLD_NAMESPACE so a buffer’s two AI fold sources register under different ids (they coexist over disjoint line regions). Distinct from diff’s 0xD1FF_* and multibuffer’s 0xBBBB_* namespaces.

Functions§

reasoning_fold_identity
Stable identity for a reasoning fold, keyed on the block’s ordinal in document order (reasoning blocks carry no wire id). Namespaced with "ai:reasoning".
tool_fold_identity
Stable identity for a tool-call fold, keyed on the wire tool_call_id (not the line range) so the fold’s expansion state survives a transcript that grows above it. Namespaced with "ai:tool" so it never collides with a primary provider’s hash for the same span.