1112 lines · 41.5 KB · Zig
RawDownload
const std = @import("std");const command_output_runtime = @import("command_output_runtime.zig");const debug_trace = @import("../../core/shared/debug_trace.zig");const transcript_release = @import("../../core/output/transcript_release.zig");const build_checkpoint = @import("../render_engine/build_checkpoint.zig");const tool_group_projection = @import("tool_group_projection.zig");const render_engine = @import("../render_engine.zig");const user_message_card = @import("../assistant/user_message_card.zig");const ui_render = @import("../render.zig");const types = @import("../../core/shared/types.zig"); const Allocator = std.mem.Allocator;const transcript_blocks = render_engine.transcript_blocks;const viewport_selection = render_engine.viewport_selection; const FoldedCommandBlock = command_output_runtime.FoldedCommandBlock;const TranscriptBuffer = viewport_selection.TranscriptBuffer;const TranscriptRef = viewport_selection.TranscriptRef;const buildHardLineStarts = viewport_selection.buildHardLineStarts;const buildHardLineStartsInterruptible = viewport_selection.buildHardLineStartsInterruptible;const hardLineRefAt = viewport_selection.hardLineRefAt;const leadingWelcomeBoundary = transcript_blocks.leadingWelcomeBoundary;const leadingWelcomeCutLine = transcript_blocks.leadingWelcomeCutLine;const stripTrailingNewline = transcript_blocks.stripTrailingNewline;const tailVisibleBlockKind = transcript_blocks.tailVisibleBlockKind;const visualRowsForLine = transcript_blocks.visualRowsForLine; test {    _ = tool_group_projection;} const FinalityNominationKind = enum { mutation_pin, tool_turn, assistant_tail }; const FinalityNomination = struct {    entry_id: u32,    kind: FinalityNominationKind,    turn_id: u64 = 0,}; const ToolFinalityIdentity = struct {    turn_id: u64,    presentation_group_id: ?types.ToolPresentationGroupId,}; const ToolTurnNomination = struct {    earliest_entry_id: u32,    selected_entry_id: u32,    selected_group_id: ?types.ToolPresentationGroupId,}; fn entryHiddenByActions(    entry_actions: []const transcript_blocks.EntryRenderAction,    index: usize,) bool {    if (entry_actions.len == 0) return false;    return entry_actions[index] == .hide;} /// Nominate the entries whose rendered start bytes bound the final flow/// prefix: the first entry carrying a live mutation pin, the first rendered/// entry of each tool turn, and a trailing assistant entry. Omitted and/// hidden entries contribute no flow bytes and are skipped.fn collectFinalityNominations(    self: anytype,    alloc: Allocator,    omitted_entry_id: ?u32,    entry_actions: []const transcript_blocks.EntryRenderAction,) !std.ArrayList(FinalityNomination) {    var nominations: std.ArrayList(FinalityNomination) = .empty;    errdefer nominations.deinit(alloc);     var entry_tool_identities: std.AutoHashMapUnmanaged(u32, ToolFinalityIdentity) = .empty;    defer entry_tool_identities.deinit(alloc);    for (self.tool_details.items) |detail| {        const identity: ToolFinalityIdentity = if (detail.presentation_group_id) |group|            .{ .turn_id = group.turn_id, .presentation_group_id = group }        else if (detail.lifecycle_id) |lifecycle|            .{ .turn_id = lifecycle.turn_id, .presentation_group_id = null }        else            continue;        try entry_tool_identities.put(alloc, detail.entry_id, identity);    }     var mutation_pin_entry_id: ?u32 = null;    var turn_nominations: std.AutoHashMapUnmanaged(u64, ToolTurnNomination) = .empty;    defer turn_nominations.deinit(alloc);    for (self.entries.items, 0..) |entry, index| {        const entry_id = entry.id();        if (omitted_entry_id == entry_id) continue;        if (entryHiddenByActions(entry_actions, index)) continue;        const tool_identity = if (entry == .raw_bytes and entry.raw_bytes.class == .tool_status)            entry_tool_identities.get(entry_id)        else            null;        if (mutation_pin_entry_id == null) {            const pinned = switch (entry) {                .raw_bytes => |raw| raw.lifecycle_pinned and tool_identity == null,                .semantic_notice => |notice| notice.pending_replacement,                else => false,            };            if (pinned) mutation_pin_entry_id = entry_id;        }         if (tool_identity) |identity| {            const result = try turn_nominations.getOrPut(alloc, identity.turn_id);            if (!result.found_existing) {                result.value_ptr.* = .{                    .earliest_entry_id = entry_id,                    .selected_entry_id = entry_id,                    .selected_group_id = identity.presentation_group_id,                };                continue;            }            const turn = result.value_ptr;            if (turn.selected_group_id == null) continue;            const group_id = identity.presentation_group_id orelse {                turn.selected_entry_id = turn.earliest_entry_id;                turn.selected_group_id = null;                continue;            };            const selected_group = turn.selected_group_id.?;            if (group_id.anchor_step_id > selected_group.anchor_step_id) {                turn.selected_entry_id = entry_id;                turn.selected_group_id = group_id;            }        }    }     for (self.entries.items, 0..) |entry, index| {        const entry_id = entry.id();        if (omitted_entry_id == entry_id) continue;        if (entryHiddenByActions(entry_actions, index)) continue;        if (mutation_pin_entry_id == entry_id) {            try nominations.append(alloc, .{                .entry_id = entry_id,                .kind = .mutation_pin,            });        }        if (entry != .raw_bytes or entry.raw_bytes.class != .tool_status) continue;        const identity = entry_tool_identities.get(entry_id) orelse continue;        const turn = turn_nominations.get(identity.turn_id).?;        if (turn.selected_entry_id != entry_id) continue;        try nominations.append(alloc, .{            .entry_id = entry_id,            .kind = .tool_turn,            .turn_id = identity.turn_id,        });    }    if (self.entries.items.len > 0) {        const tail = self.entries.items[self.entries.items.len - 1];        if (tail == .assistant_turn and            omitted_entry_id != tail.id() and            !entryHiddenByActions(entry_actions, self.entries.items.len - 1))        {            try nominations.append(alloc, .{                .entry_id = tail.id(),                .kind = .assistant_tail,            });        }    }    return nominations;} pub const TranscriptPreparationSource = struct {    bytes: []u8,    folded_summary_indices: []usize,    line_provenance: []const transcript_blocks.LineProvenance = &.{},    preview: render_engine.frame_layout.TranscriptFlowPreview,    tail_kind: ?transcript_blocks.TranscriptBlockKind,    tracked_entry_id: ?u32,    tracked_entry_start_line: ?usize,    replaceable_last_line: bool,    replaceable_start: usize,    replaceable_row: u16,    welcome_cut_line: ?usize,    welcome_boundary: ?transcript_blocks.LeadingWelcomeBoundary,    cols: u16,    recorded_entries_authoritative: bool = false,    cache_origin_untrimmed: bool = false,    hard_line_starts: []usize = &.{},    hard_lines_end_with_newline: bool = false,    transcript_visible_lines: []viewport_selection.VisibleTranscriptLine = &.{},    transcript_line_visual_rows: []u16 = &.{},    transcript_visual_row_offsets: []u32 = &.{},    finality: transcript_release.Candidates = .{},     pub fn deinit(self: *TranscriptPreparationSource, alloc: Allocator) void {        if (self.bytes.len > 0) alloc.free(self.bytes);        if (self.folded_summary_indices.len > 0) alloc.free(self.folded_summary_indices);        if (self.line_provenance.len > 0) alloc.free(self.line_provenance);        if (self.hard_line_starts.len > 0) alloc.free(self.hard_line_starts);        if (self.transcript_visible_lines.len > 0) alloc.free(self.transcript_visible_lines);        if (self.transcript_line_visual_rows.len > 0) alloc.free(self.transcript_line_visual_rows);        if (self.transcript_visual_row_offsets.len > 0) alloc.free(self.transcript_visual_row_offsets);        self.finality.deinit(alloc);        self.* = undefined;    }     pub fn ensureLineIndex(self: *TranscriptPreparationSource, alloc: Allocator) !void {        return self.ensureLineIndexInterruptible(alloc, null) catch |err| switch (err) {            error.InputPending => unreachable,            else => |other| return other,        };    }     pub fn ensureLineIndexInterruptible(        self: *TranscriptPreparationSource,        alloc: Allocator,        checkpoint: ?*build_checkpoint.BuildCheckpoint,    ) !void {        if (self.bytes.len == 0) return build_checkpoint.poll(checkpoint);        if (self.hard_line_starts.len > 0) return;        const hard_lines = try buildHardLineStartsInterruptible(alloc, self.bytes, checkpoint);        errdefer hard_lines.deinit(alloc);        const line_visual_rows = try alloc.alloc(u16, hard_lines.len());        errdefer alloc.free(line_visual_rows);        const visible_lines = try alloc.alloc(viewport_selection.VisibleTranscriptLine, hard_lines.len());        errdefer alloc.free(visible_lines);        const visual_row_offsets = try alloc.alloc(u32, hard_lines.len() + 1);        errdefer alloc.free(visual_row_offsets);        visual_row_offsets[0] = 0;        const transcript = TranscriptBuffer{ .bytes = self.bytes };        for (line_visual_rows, visible_lines, 0..) |*rows, *line, index| {            const ref = hardLineRefAt(hard_lines, self.bytes.len, index);            const bytes = (TranscriptRef{ .ref = ref }).resolve(transcript);            try build_checkpoint.consume(checkpoint, bytes.len);            rows.* = visualRowsForLine(bytes, self.cols);            line.* = viewport_selection.visibleFromTranscript(ref);            visual_row_offsets[index + 1] = visual_row_offsets[index] + rows.*;        }        self.hard_line_starts = hard_lines.starts;        self.hard_lines_end_with_newline = hard_lines.ends_with_newline;        self.transcript_visible_lines = visible_lines;        self.transcript_line_visual_rows = line_visual_rows;        self.transcript_visual_row_offsets = visual_row_offsets;    }     pub fn clone(self: *const TranscriptPreparationSource, alloc: Allocator) !TranscriptPreparationSource {        const bytes = try alloc.dupe(u8, self.bytes);        errdefer alloc.free(bytes);        const folded_summary_indices = try alloc.dupe(usize, self.folded_summary_indices);        errdefer alloc.free(folded_summary_indices);        const line_provenance = try alloc.dupe(            transcript_blocks.LineProvenance,            self.line_provenance,        );        errdefer alloc.free(line_provenance);        const hard_line_starts = try alloc.dupe(usize, self.hard_line_starts);        errdefer alloc.free(hard_line_starts);        const transcript_visible_lines = try alloc.dupe(            viewport_selection.VisibleTranscriptLine,            self.transcript_visible_lines,        );        errdefer alloc.free(transcript_visible_lines);        const transcript_line_visual_rows = try alloc.dupe(u16, self.transcript_line_visual_rows);        errdefer alloc.free(transcript_line_visual_rows);        const transcript_visual_row_offsets = try alloc.dupe(u32, self.transcript_visual_row_offsets);        errdefer alloc.free(transcript_visual_row_offsets);        var finality = try self.finality.clone(alloc);        errdefer finality.deinit(alloc);        return .{            .bytes = bytes,            .folded_summary_indices = folded_summary_indices,            .line_provenance = line_provenance,            .preview = self.preview,            .tail_kind = self.tail_kind,            .tracked_entry_id = self.tracked_entry_id,            .tracked_entry_start_line = self.tracked_entry_start_line,            .replaceable_last_line = self.replaceable_last_line,            .replaceable_start = self.replaceable_start,            .replaceable_row = self.replaceable_row,            .welcome_cut_line = self.welcome_cut_line,            .welcome_boundary = self.welcome_boundary,            .cols = self.cols,            .recorded_entries_authoritative = self.recorded_entries_authoritative,            .cache_origin_untrimmed = self.cache_origin_untrimmed,            .hard_line_starts = hard_line_starts,            .hard_lines_end_with_newline = self.hard_lines_end_with_newline,            .transcript_visible_lines = transcript_visible_lines,            .transcript_line_visual_rows = transcript_line_visual_rows,            .transcript_visual_row_offsets = transcript_visual_row_offsets,            .finality = finality,        };    }}; pub fn prepareTranscriptSource(    self: anytype,    alloc: Allocator,    tracked_entry_id: ?u32,) !TranscriptPreparationSource {    return prepareTranscriptSourceInternal(self, alloc, tracked_entry_id, null, null, null) catch |err| switch (err) {        error.InputPending => unreachable,        else => |other| return other,    };} pub fn prepareTranscriptSourceWithFocusedEntry(    self: anytype,    alloc: Allocator,    focused_entry_id: u32,) !TranscriptPreparationSource {    return prepareTranscriptSourceInternal(self, alloc, focused_entry_id, focused_entry_id, null, null) catch |err| switch (err) {        error.InputPending => unreachable,        else => |other| return other,    };} pub fn prepareTranscriptSourceOmittingEntry(    self: anytype,    alloc: Allocator,    omitted_entry_id: u32,) !TranscriptPreparationSource {    return prepareTranscriptSourceInternal(self, alloc, null, null, omitted_entry_id, null) catch |err| switch (err) {        error.InputPending => unreachable,        else => |other| return other,    };} pub fn prepareTranscriptSourceInterruptible(    self: anytype,    alloc: Allocator,    tracked_entry_id: ?u32,    focused_entry_id: ?u32,    omitted_entry_id: ?u32,    checkpoint: ?*build_checkpoint.BuildCheckpoint,) !TranscriptPreparationSource {    return prepareTranscriptSourceInternal(        self,        alloc,        tracked_entry_id,        focused_entry_id,        omitted_entry_id,        checkpoint,    );} pub fn renderCompactTranscriptBytes(    self: anytype,    alloc: Allocator,) ![]u8 {    var command_overrides = try buildCommandOutputOverrides(self, alloc);    defer command_overrides.deinit(alloc);    const styles = self.command_output_render.styles;     if (self.maxxing_mode == .legacy) {        const entry_actions = try buildCommandOutputActions(            alloc,            &command_overrides,            self.entries.items.len,        );        defer if (entry_actions.len > 0) alloc.free(entry_actions);        return transcript_blocks.renderEntriesWithProjectionToBytes(            alloc,            self.entries.items,            self.layout.cols,            styles,            entry_actions,            self.maxxing_mode,        );    }     var projection = try buildMinimalTranscriptProjection(        self,        alloc,        &command_overrides,        null,    );    defer projection.deinit(alloc);    return transcript_blocks.renderEntriesWithProjectionToBytes(        alloc,        self.entries.items,        self.layout.cols,        styles,        projection.entry_actions.items,        self.maxxing_mode,    );} /// Takes ownership of a bounded full-transcript visual window and prepares it/// for the ordinary transcript surface painter. Ctrl-O uses this only after/// the full document source has selected its current visual window.pub fn prepareFullTranscriptViewportSource(    self: anytype,    alloc: Allocator,    bytes: []u8,) !TranscriptPreparationSource {    return prepareFullTranscriptViewportSourceInterruptible(self, alloc, bytes, null) catch |err| switch (err) {        error.InputPending => unreachable,        else => |other| return other,    };} pub fn prepareFullTranscriptViewportSourceInterruptible(    self: anytype,    alloc: Allocator,    bytes: []u8,    checkpoint: ?*build_checkpoint.BuildCheckpoint,) !TranscriptPreparationSource {    errdefer alloc.free(bytes);    const line_provenance = if (observationEnabled(self, alloc))        try unattributedLineProvenance(alloc, bytes)    else        &.{};    errdefer if (line_provenance.len > 0) alloc.free(line_provenance);    const tail_kind = tailVisibleBlockKind(self.entries.items);    const preview = try transcriptFlowPreviewFromSourceInterruptible(        self,        alloc,        bytes,        &.{},        0,        false,        tail_kind,        checkpoint,    );    return .{        .bytes = bytes,        .folded_summary_indices = try alloc.alloc(usize, 0),        .line_provenance = line_provenance,        .preview = preview,        .tail_kind = tail_kind,        .tracked_entry_id = null,        .tracked_entry_start_line = null,        .replaceable_last_line = false,        .replaceable_start = 0,        .replaceable_row = self.replaceable_row,        .welcome_cut_line = null,        .welcome_boundary = null,        .cols = self.layout.cols,    };} fn prepareTranscriptSourceInternal(    self: anytype,    alloc: Allocator,    tracked_entry_id: ?u32,    focused_entry_id: ?u32,    omitted_entry_id: ?u32,    checkpoint: ?*build_checkpoint.BuildCheckpoint,) !TranscriptPreparationSource {    var bytes: []u8 = &.{};    errdefer if (bytes.len > 0) alloc.free(bytes);    var folded_summary_indices: []usize = &.{};    errdefer if (folded_summary_indices.len > 0) alloc.free(folded_summary_indices);    var line_provenance: []const transcript_blocks.LineProvenance = &.{};    errdefer if (line_provenance.len > 0) alloc.free(line_provenance);    var trailing_boundary_blank_rows: u16 = 0;    var tracked_entry_start_line: ?usize = null;    var replaceable_entry_start_byte: ?usize = null;    var rendered_from_entries = false;     var command_overrides = try buildCommandOutputOverridesInterruptible(self, alloc, checkpoint);    defer command_overrides.deinit(alloc);    var minimal_projection: ?tool_group_projection.Projection = null;    defer if (minimal_projection) |*projection| projection.deinit(alloc);    if (self.maxxing_mode == .minimal and self.entries.items.len > 0 and self.layout.cols > 0) {        minimal_projection = try buildMinimalTranscriptProjectionInterruptible(            self,            alloc,            &command_overrides,            focused_entry_id,            checkpoint,        );    }     const aligned_actions = if (minimal_projection == null)        try buildCommandOutputActions(            alloc,            &command_overrides,            self.entries.items.len,        )    else        &.{};    defer if (aligned_actions.len > 0) alloc.free(aligned_actions);     const entry_actions = if (minimal_projection) |*projection|        projection.entry_actions.items    else        aligned_actions;     var finality: transcript_release.Candidates = .{};    errdefer finality.deinit(alloc);    if (self.entries.items.len > 0 and self.layout.cols > 0) {        rendered_from_entries = true;        const capture_provenance = observationEnabled(self, alloc) or            self.command_output_blocks.items.len > 0;        const replaceable_entry_id: ?u32 = if (self.replaceable_last_line and            self.entries.items[self.entries.items.len - 1] == .raw_bytes)            self.entries.items[self.entries.items.len - 1].raw_bytes.id        else            null;        var finality_nominations = try collectFinalityNominations(            self,            alloc,            omitted_entry_id,            entry_actions,        );        defer finality_nominations.deinit(alloc);        const finality_entry_ids = try alloc.alloc(u32, finality_nominations.items.len);

Lines 1–500 of 1112.