588 lines · 21.1 KB · Zig
RawDownload
const std = @import("std");const types = @import("../../shared/types.zig");const debug_trace = @import("../../shared/debug_trace.zig");const diff = @import("../../output/diff.zig");const tool_dispatch = @import("../../tooling/tool_dispatch.zig");const tool_result_errors = @import("../../tooling/tool_result_errors.zig"); const runtime_config = @import("config.zig");const runtime_execution_memory = @import("execution_memory.zig");const runtime_deps = @import("deps.zig");const runtime_interruption = @import("interruption.zig");const runtime_parallel_execution = @import("parallel_execution.zig");const runtime_telemetry = @import("telemetry.zig");const runtime_tool_admission = @import("tool_admission.zig");const runtime_tool_contracts = @import("tool_contracts.zig");const runtime_tool_presentation = @import("tool_presentation.zig"); const Allocator = std.mem.Allocator;const ChatMessage = types.ChatMessage;const ToolCall = types.ToolCall;const TraceContext = debug_trace.TraceContext;const AgentRuntimeDeps = runtime_deps.AgentRuntimeDeps;const ToolExecutionResult = runtime_tool_contracts.ToolExecutionResult; pub const StepBatchState = struct {    step_error_count: usize = 0,    step_total_count: usize = 0,    step_had_writes: bool = false,    pending_user_suffix: std.ArrayList(ChatMessage) = .empty,     pub fn allToolResultsFailed(self: StepBatchState) bool {        return self.step_total_count > 0 and self.step_error_count == self.step_total_count;    }}; pub const ToolResultAccounting = struct {    increment_total: bool = true,    increment_error: bool = false,    record_completion: bool = false,    mark_write: bool = false,    status: ?types.PersistedToolStatus = null,}; pub fn appendAssistantToolCallStep(    arena: Allocator,    within_turn_suffix: *std.ArrayList(ChatMessage),    content: ?[]const u8,    tool_calls: []const ToolCall,) !void {    try within_turn_suffix.append(arena, .{ .role = .assistant, .content = content, .tool_calls = tool_calls });} pub fn appendToolResultContent(    arena: Allocator,    within_turn_suffix: *std.ArrayList(ChatMessage),    completed_tool_names: *std.ArrayList([]u8),    batch: *StepBatchState,    tool_call: ToolCall,    model_output: []const u8,    memory: ?types.ToolResultMemory,    accounting: ToolResultAccounting,) !void {    if (accounting.increment_total) batch.step_total_count += 1;    if (accounting.increment_error) batch.step_error_count += 1;    if (accounting.mark_write) batch.step_had_writes = true;    try within_turn_suffix.append(arena, .{        .role = .tool,        .content = model_output,        .tool_call_id = tool_call.id,        .tool_name = tool_call.name,        .tool_result_status = accounting.status orelse            if (accounting.increment_error) .failure else .success,        .tool_result_memory = memory,    });    if (accounting.record_completion) {        try runtime_interruption.recordCompletedToolName(arena, completed_tool_names, tool_call.name);    }} pub fn appendPermissionFeedback(    arena: Allocator,    batch: *StepBatchState,    source_tool_call_id: []const u8,    feedback: []const []const u8,) !void {    for (feedback) |text| {        if (text.len == 0) continue;        const owned = try arena.dupe(u8, text);        try batch.pending_user_suffix.append(arena, .{            .role = .user,            .content = owned,            .tool_call_id = source_tool_call_id,            .permission_feedback = true,        });    }} pub fn drainPendingUserSuffix(    arena: Allocator,    batch: *StepBatchState,    within_turn_suffix: *std.ArrayList(ChatMessage),) !void {    try within_turn_suffix.appendSlice(arena, batch.pending_user_suffix.items);    batch.pending_user_suffix.clearRetainingCapacity();} pub fn reserveCommittedFileBookkeeping(    arena: Allocator,    within_turn_suffix: *std.ArrayList(ChatMessage),    completed_tool_names: *std.ArrayList([]u8),    tool_name: []const u8,) ![]u8 {    try within_turn_suffix.ensureUnusedCapacity(arena, 1);    try completed_tool_names.ensureUnusedCapacity(arena, 1);    return try arena.dupe(u8, tool_name);} pub fn assembleParallelToolResults(    arena: Allocator,    hooks: *const AgentRuntimeDeps,    config: runtime_config.Config,    within_turn_suffix: *std.ArrayList(ChatMessage),    completed_tool_names: *std.ArrayList([]u8),    batch: *StepBatchState,    provisional_statuses: *runtime_tool_presentation.ProvisionalToolStatuses,    provisional_alloc: Allocator,    parallel_calls: []const ToolCall,    precomputed_results: []const ?ToolExecutionResult,    parallel_attempts: []const runtime_parallel_execution.ParallelToolAttempt,    parallel_status_started: []const bool,    parallel_status_terminalized: []const bool,    turn_id: u64,    advertised_dynamic_tool_names: []const []const u8,    step_ctx: TraceContext,) !?ToolCall {    var parallel_result_index: usize = 0;    var cancelled_call: ?ToolCall = null;    for (parallel_calls, precomputed_results, 0..) |original_call, precomputed, original_index| {        const execution = precomputed orelse blk: {            const attempt = parallel_attempts[parallel_result_index];            parallel_result_index += 1;            switch (attempt) {                .completed => |result| break :blk result.execution,                .cancelled => {                    if (cancelled_call == null) cancelled_call = original_call;                    _ = try provisional_statuses.finishDeniedCall(                        hooks,                        provisional_alloc,                        arena,                        turn_id,                        original_call,                        parallel_status_started[original_index],                        null,                        "Cancelled",                        advertised_dynamic_tool_names,                    );                    continue;                },            }        };        var prepared = try runtime_execution_memory.prepareToolModelOutput(arena, config, original_call, execution.model_output);        runtime_execution_memory.applyToolResultMemory(            &prepared.memory,            execution.tool_result_memory,        );        const safe_tool_output = prepared.model_output;        if (precomputed == null) {            runtime_parallel_execution.reportInnerToolUsage(hooks, original_call.name, execution);            _ = try provisional_statuses.finishExecutedCall(                hooks,                provisional_alloc,                arena,                turn_id,                original_call,                parallel_status_started[original_index],                null,                execution,                safe_tool_output,                prepared.memory,                null,                advertised_dynamic_tool_names,            );            debug_trace.eventf("tool", "after_tool_execution", step_ctx, "call_id={s} name={s} result_kind={s} model_output_bytes={d}", .{ original_call.id, original_call.name, runtime_telemetry.toolExecutionResultKind(execution), safe_tool_output.len });            if (hooks.tool_activity_recorder) |recorder| {                const phase: runtime_deps.ToolActivityPhase = if (execution.status == .success)                    .succeeded                else                    .failed;                recorder.record(original_call.id, original_call.name, phase) catch |err| {                    debug_trace.eventf(                        "subagent",                        "tool_activity_projection_lag",                        step_ctx,                        "call_id={s} tool_name={s} phase={s} outcome={s}",                        .{                            original_call.id,                            original_call.name,                            @tagName(phase),                            @errorName(err),                        },                    );                };            }        } else if (original_call.argument_integrity == .malformed_json) {            try provisional_statuses.finishMalformedToolArguments(                hooks,                arena,                turn_id,                original_call,            );            debug_trace.eventf(                "tool",                "argument_integrity_rejected",                step_ctx,                "call_id={s} name={s} failure=malformed_json provenance=fx_local",                .{ original_call.id, original_call.name },            );            try runtime_tool_admission.recordRejectedToolCall(                hooks,                arena,                original_call,                safe_tool_output,                null,            );        } else if (!parallel_status_terminalized[original_index]) {            _ = try provisional_statuses.finishExecutedCall(                hooks,                provisional_alloc,                arena,                turn_id,                original_call,                parallel_status_started[original_index],                null,                execution,                safe_tool_output,                prepared.memory,                null,                advertised_dynamic_tool_names,            );        }        for (execution.context_notices) |notice| {            try hooks.pushContextNotice(notice);        }        debug_trace.eventf("tool", "execution_result", step_ctx, "call_id={s} name={s} result_kind={s} model_output_bytes={d}", .{ original_call.id, original_call.name, runtime_telemetry.toolExecutionResultKind(execution), safe_tool_output.len });        try appendToolResultContent(            arena,            within_turn_suffix,            completed_tool_names,            batch,            original_call,            safe_tool_output,            prepared.memory,            .{                .increment_error = execution.status == .failure or tool_result_errors.isToolOutputError(safe_tool_output),                .record_completion = execution.status == .success,                .status = runtime_execution_memory.persistedStatusForCurrentFxLocalResult(                    execution.status,                    safe_tool_output,                ),            },        );    }    return cancelled_call;} pub fn processCommittedFileResult(    hooks: *const AgentRuntimeDeps,    presentation_allocator: Allocator,    history_allocator: Allocator,    within_turn_suffix: *std.ArrayList(ChatMessage),    completed_tool_names: *std.ArrayList([]u8),    batch: *StepBatchState,    tool_call: ToolCall,    execution_call: ToolCall,    execution: ToolExecutionResult,    committed_file_tool_name: []u8,    status_started: bool,    file_display_path: ?[]const u8,    is_file_mutation: bool,    turn_id: u64,    advertised_dynamic_tool_names: []const []const u8,    step_ctx: TraceContext,) !void {    if (!is_file_mutation) {        return error.InvalidCommittedFileExecutionResult;    }    const handoff = execution.committed_file_handoff orelse unreachable;    if (hooks.usage) |usage| {        usage.recordCommittedLines(            handoff.preview.additions,            handoff.preview.deletions,        ) catch |err| {            debug_trace.logf(                "session",                "usage code accounting failed additions={d} deletions={d} reason={s}",                .{                    handoff.preview.additions,                    handoff.preview.deletions,                    @errorName(err),                },            );            usage.markCodeIncomplete();        };        if (!usage.persistCheckpoint()) usage.markCodeIncomplete();    }    const committed_contract_degraded =        execution.status != .success or        execution.prepared_result_memory == null or        execution.diff_entry != null or        execution.display_output != null or        execution.finish_turn;    if (committed_contract_degraded) {        debug_trace.eventf(            "tool",            "committed_result_contract_degraded",            step_ctx,            "call_id={s} name={s} status={s} memory={s} diff={s} display={s} finish_turn={s}",            .{                tool_call.id,                tool_call.name,                @tagName(execution.status),                if (execution.prepared_result_memory != null) "true" else "false",                if (execution.diff_entry != null) "true" else "false",                if (execution.display_output != null) "true" else "false",                if (execution.finish_turn) "true" else "false",            },        );        if (execution.diff_entry) |payload| {            diff.freeDiffEntryPayload(std.heap.c_allocator, payload);        }    }     var prepared_memory = execution.prepared_result_memory orelse        types.ToolResultMemory{            .output_bytes = execution.model_output.len,            .stored_output_bytes = execution.model_output.len,        };    prepared_memory.committed_file_presentation = runtime_execution_memory.captureCommittedFilePresentation(        history_allocator,        handoff,    ) catch |err| blk: {        debug_trace.logf(            "session",            "committed file resume presentation unavailable call_id={s} err={s}",            .{ tool_call.id, @errorName(err) },        );        break :blk null;    };    within_turn_suffix.appendAssumeCapacity(.{        .role = .tool,        .content = execution.model_output,        .tool_call_id = tool_call.id,        .tool_name = tool_call.name,        .tool_result_status = runtime_execution_memory.persistedStatusForCurrentFxLocalResult(            execution.status,            execution.model_output,        ),        .tool_result_memory = prepared_memory,    });    debug_trace.eventf(        "tool",        "committed_result_appended",        step_ctx,        "call_id={s} name={s} model_output_bytes={d}",        .{ tool_call.id, tool_call.name, execution.model_output.len },    );     const publication = hooks.publish_committed_file_handoff(        hooks.ctx,        handoff,    );    debug_trace.eventf(        "tool",        "committed_secondary_publication",        step_ctx,        "call_id={s} name={s} diff={s} tracker={s}",        .{            tool_call.id,            tool_call.name,            @tagName(publication.diff),            @tagName(publication.tracker),        },    );    var reporting_degraded =        publication.degraded() or committed_contract_degraded;    runtime_tool_presentation.finishCommittedFileStatus(        hooks,        presentation_allocator,        turn_id,        execution_call,        status_started,        file_display_path,        handoff.preview,        advertised_dynamic_tool_names,    ) catch |err| {        reporting_degraded = true;        debug_trace.eventf(            "tool",            "committed_status_publication_failed",            step_ctx,            "call_id={s} name={s} err={s}",            .{ tool_call.id, tool_call.name, @errorName(err) },        );    };    if (execution.deferred_tool_completion) |deferred_completion| {        if (hooks.publish_deferred_tool_completion) |publish_deferred| {            const outcome = publish_deferred(                hooks.ctx,                deferred_completion,            );            if (outcome == .failed) reporting_degraded = true;            debug_trace.eventf(                "tool",                "deferred_tool_completion_publication",                step_ctx,                "call_id={s} name={s} outcome={s}",                .{ tool_call.id, tool_call.name, @tagName(outcome) },            );        } else {            reporting_degraded = true;            debug_trace.eventf(                "tool",                "deferred_tool_completion_publication",                step_ctx,                "call_id={s} name={s} outcome=missing_publisher",                .{ tool_call.id, tool_call.name },            );        }    }    if (reporting_degraded) {        hooks.push_system_notice(            hooks.ctx,            "File change committed, but some secondary reporting failed.",        ) catch |err| {            debug_trace.eventf(                "tool",                "committed_reporting_warning_failed",                step_ctx,                "call_id={s} name={s} err={s}",                .{ tool_call.id, tool_call.name, @errorName(err) },            );        };    }     debug_trace.eventf(        "tool",        "after_tool_execution",        step_ctx,        "call_id={s} name={s} result_kind=committed_file model_output_bytes={d}",        .{ tool_call.id, tool_call.name, execution.model_output.len },    );    debug_trace.eventf(        "tool",        "execution_result",        step_ctx,        "call_id={s} name={s} result_kind=committed_file model_output_bytes={d}",        .{ tool_call.id, tool_call.name, execution.model_output.len },    );    batch.step_total_count += 1;    batch.step_had_writes = true;    completed_tool_names.appendAssumeCapacity(committed_file_tool_name);} pub fn appendOrdinaryExecutedResult(    tool_registry: tool_dispatch.Registry,    arena: Allocator,    within_turn_suffix: *std.ArrayList(ChatMessage),    completed_tool_names: *std.ArrayList([]u8),    batch: *StepBatchState,    tool_call: ToolCall,    model_output: []const u8,    memory: types.ToolResultMemory,    execution: ToolExecutionResult,) !void {    const activity = runtime_tool_presentation.activityKindForCall(arena, tool_registry, tool_call);    try appendToolResultContent(        arena,        within_turn_suffix,        completed_tool_names,        batch,        tool_call,        model_output,        memory,        .{            .increment_error = execution.status == .failure or tool_result_errors.isToolOutputError(model_output),            .record_completion = true,            .mark_write = activity == .write or activity == .edit,            .status = runtime_execution_memory.persistedStatusForCurrentFxLocalResult(                execution.status,                model_output,            ),        },    );} pub fn appendReviewContinuationSuffix(    review_enabled: bool,    arena: Allocator,    within_turn_suffix: *std.ArrayList(ChatMessage),    batch: *const StepBatchState,

Lines 1–500 of 588.