PranitInitial commit439f83c2 months agoHistory
198 lines · 5.9 KB · Zig
RawDownload
const std = @import("std");const hooks = @import("../../hooks/hooks.zig");const types = @import("../../shared/types.zig");const debug_trace = @import("../../shared/debug_trace.zig");const deps_mod = @import("deps.zig");const execution_memory = @import("execution_memory.zig");const lifecycle_runtime = @import("lifecycle.zig");const telemetry = @import("telemetry.zig");const worker_runtime = @import("../worker_runtime.zig"); const Allocator = std.mem.Allocator;const AgentRuntimeDeps = deps_mod.AgentRuntimeDeps;const ChatMessage = types.ChatMessage;const HistoryTurn = types.HistoryTurn;const LifecycleContext = lifecycle_runtime.LifecycleContext;const QueuedPrompt = worker_runtime.QueuedPrompt;const TraceContext = debug_trace.TraceContext;const TurnSummaryAccumulator = telemetry.TurnSummaryAccumulator; pub const PromptFinishTrace = struct {    ctx: TraceContext,    emitted: bool = false,     pub fn finish(self: *PromptFinishTrace, outcome: []const u8) void {        if (self.emitted) return;        self.emitted = true;        debug_trace.eventf("agent", "prompt_finish", self.ctx, "outcome_kind={s}", .{outcome});    }}; pub const TurnFinalizationGuard = struct {    pub const State = enum {        open,        emitted,        fatal,    };     deps: *const AgentRuntimeDeps,    turn_id: u64,    lifecycle: LifecycleContext,    state: State = .open,     pub fn init(        deps: *const AgentRuntimeDeps,        turn_id: u64,        lifecycle_context: LifecycleContext,    ) TurnFinalizationGuard {        std.debug.assert(turn_id != 0);        return .{            .deps = deps,            .turn_id = turn_id,            .lifecycle = lifecycle_context,        };    }     pub fn finish(        self: *TurnFinalizationGuard,        outcome: types.TurnPresentationOutcome,        disposition: ?types.ProviderCompletionDisposition,        finished_prompt: ?types.FinishedPrompt,    ) !void {        if (self.state != .open) {            if (finished_prompt) |finished| {                types.freeFinishedPrompt(std.heap.c_allocator, finished);            }            debug_trace.logf(                "agent",                "duplicate turn finalization ignored turn_id={d} state={s}",                .{ self.turn_id, @tagName(self.state) },            );            return;        }         self.deps.finalize_turn(self.deps.ctx, self.turn_id, outcome, disposition) catch |err| {            self.state = .fatal;            if (finished_prompt) |finished| {                types.freeFinishedPrompt(std.heap.c_allocator, finished);            }            return err;        };        self.state = .emitted;         defer lifecycle_runtime.dispatchPostTurnEndCheckpoint(self.lifecycle, .{            .turn_id = self.turn_id,            .outcome = outcome,            .provider_disposition = disposition,        });         if (finished_prompt) |finished| {            var qualified_finished = finished;            qualified_finished.terminal_outcome = outcome;            try self.deps.push_event(self.deps.ctx, .{ .finish_prompt = qualified_finished });        }    }}; pub fn finishAssistantTerminalWithExecution(    deps: *const AgentRuntimeDeps,    finalization: *TurnFinalizationGuard,    job: QueuedPrompt,    execution: types.ExecutionMemory,    summary: *TurnSummaryAccumulator,    assistant_text: []const u8,    outcome: types.TurnPresentationOutcome,    disposition: ?types.ProviderCompletionDisposition,    finish_trace: *PromptFinishTrace,    trace_outcome: []const u8,) !void {    const turn: HistoryTurn = .{ .assistant = .{        .user = .{ .text = job.prompt, .images = job.images },        .assistant = @constCast(assistant_text),        .execution = execution,    } };    const finished = try types.dupeFinishedPrompt(        std.heap.c_allocator,        .{            .turn = turn,            .summary = summary.finish(),        },    );     var propagation_error: ?anyerror = null;    deps.propagate_history_turn(deps.ctx, turn) catch |err| {        propagation_error = err;    };    try finalization.finish(outcome, disposition, finished);    finish_trace.finish(trace_outcome);    if (propagation_error) |err| return err;} pub fn finishExecutionOnlyFailureIfNeeded(    deps: *const AgentRuntimeDeps,    finalization: *TurnFinalizationGuard,    arena: Allocator,    job: QueuedPrompt,    current_turn_messages: []const ChatMessage,    summary: *TurnSummaryAccumulator,    finish_trace: *PromptFinishTrace,    terminal_materializing: *bool,    trace_outcome: []const u8,) !bool {    const execution = try execution_memory.buildExecutionMemory(        arena,        current_turn_messages,    );    if (execution.isEmpty()) return false;     terminal_materializing.* = true;    try finishAssistantTerminalWithExecution(        deps,        finalization,        job,        execution,        summary,        "",        .failed,        null,        finish_trace,        trace_outcome,    );    return true;} pub fn finalizeRetainedCandidateFailure(    deps: *const AgentRuntimeDeps,    finalization: *TurnFinalizationGuard,    arena: Allocator,    job: QueuedPrompt,    current_turn_messages: []const ChatMessage,    summary: *TurnSummaryAccumulator,    finish_trace: *PromptFinishTrace,    retained_candidate: ?[]const u8,    latest_partial: ?[]const u8,    terminal_materializing: *bool,) !void {    terminal_materializing.* = true;    const assistant_text = try hooks.prompt.joinVisibleSegments(        arena,        retained_candidate,        latest_partial,    );    const execution = try execution_memory.buildExecutionMemory(        arena,        current_turn_messages,    );    try finishAssistantTerminalWithExecution(        deps,        finalization,        job,        execution,        summary,        assistant_text,        .failed,        null,        finish_trace,        "error",    );}