Something went wrong. Try again.
My version of https://github.com/vercel-labs/fx
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217const std = @import("std");const builtin = @import("builtin");const agent_stream_provider = @import("../../stream_provider.zig");const command_admission = @import("../../../permissions/command_admission.zig");const permission_auto_classifier = @import("../../../permissions/auto_classifier.zig");const types = @import("../../../shared/types.zig");const permissions = @import("../../../permissions/permissions.zig");const worker_runtime = @import("../../worker_runtime.zig");const builtin_context = @import("../../../../builtins/context.zig");const builtin_gateway = @import("../../../../builtins/gateway.zig");const builtin_tools = @import("../../../../builtins/tools.zig");const session_runtime = @import("../../../session/session.zig");const session_codec = @import("../../../session/session_codec.zig");const session_usage = @import("../../../session/session_usage.zig");const model_provider = @import("../../../config/model_provider.zig");const command_replay_store = @import("../../../session/command_replay_store.zig");const session_child_store = @import("../../../session/session_child_store.zig");const lifecycle_hooks = @import("../../../hooks/hooks.zig");const model_capabilities = @import("../../../config/model_capabilities.zig");const provider_set = @import("../../../gateway/provider_set.zig");const file_mutation = @import("../../../tooling/file_mutation.zig");const file_mutation_contract = @import("../../../tooling/file_mutation_contract.zig");const context_contract = @import("../../../workspace/context_contract.zig");const io_mod = @import("../../../shared/io.zig");const pathing = @import("../../../workspace/pathing.zig");const tool_dispatch = @import("../../../tooling/tool_dispatch.zig");const tool_runtime = @import("../../../tooling/tool_runtime.zig");const command_output_content = @import("../../../tooling/command_output_content.zig");const testing_write_file = if (builtin.is_test) @import("../../../../tools/filesystem/write_file.zig")else struct {};const testing_edit_file = if (builtin.is_test) @import("../../../../tools/filesystem/edit_file.zig")else struct {};
const runtime_config = @import("../config.zig");const runtime_deps = @import("../deps.zig");const runtime_lifecycle = @import("../lifecycle.zig");const runtime_agent = @import("../agent.zig");const model_response_recovery = @import("../model_response_recovery.zig");const runtime_orchestrator = @import("../orchestrator.zig");const runtime_tool_contracts = @import("../tool_contracts.zig");
const Allocator = std.mem.Allocator;const ChatMessage = types.ChatMessage;const HistoryTurn = types.HistoryTurn;const PermissionGrant = types.PermissionGrant;const PermissionMode = types.PermissionMode;const ToolCall = types.ToolCall;const ToolPermissionDecision = types.ToolPermissionDecision;const QueuedPrompt = worker_runtime.QueuedPrompt;const WorkerEvent = worker_runtime.WorkerEvent;const AgentRuntimeDeps = runtime_deps.AgentRuntimeDeps;const Config = runtime_config.Config;const ToolExecutionResult = runtime_tool_contracts.ToolExecutionResult;const ToolExecutionRequest = runtime_tool_contracts.ToolExecutionRequest;const ToolCallValidationResult = runtime_tool_contracts.ToolCallValidationResult;const DiffEntryPayload = runtime_tool_contracts.DiffEntryPayload;const SecondaryPublicationReport = runtime_tool_contracts.SecondaryPublicationReport;
pub const vision_agent_test_tools = [_]tool_dispatch.Tool{builtin_tools.vision};
pub const VisionAgentToolRuntime = struct { alloc: Allocator, workspace_root: []const u8 = "/tmp/workspace", session_id: ?[]const u8 = null, agent_stream_provider: agent_stream_provider.Provider = agent_stream_provider.unavailable_provider, result_allocator_override: ?Allocator = null, execution_count: usize = 0, result_count: usize = 0, worker: worker_runtime.WorkerRuntime = .{}, session: session_runtime.SessionRuntime = .{ .max_history_turns = 8 },
pub fn deinit(self: *VisionAgentToolRuntime) void { self.worker.deinit(self.alloc); self.session.deinit(self.alloc); }
pub fn delegate(self: *VisionAgentToolRuntime) ExecuteDelegate { return .{ .ctx = self, .run = execute, .set_agent_stream_provider = setAgentStreamProvider, }; }
fn setAgentStreamProvider(raw: *anyopaque, provider: agent_stream_provider.Provider) void { const self: *VisionAgentToolRuntime = @ptrCast(@alignCast(raw)); self.agent_stream_provider = provider; }
fn execute(raw: *anyopaque, request: ToolExecutionRequest) !ToolExecutionResult { const self: *VisionAgentToolRuntime = @ptrCast(@alignCast(raw)); self.execution_count += 1; var effective_request = request; effective_request.result_allocator = self.result_allocator_override orelse request.result_allocator; const result = try tool_runtime.executeToolCallAuthorized( self.context(), effective_request, ); self.result_count += 1; return result; }
fn context(self: *VisionAgentToolRuntime) tool_runtime.Context { return .{ .workspace_root = self.workspace_root, .ignored_list_entries = &.{}, .max_list_entries = 100, .max_read_file_bytes = 64 * 1024, .max_read_file_lines = 400, .max_read_file_line_len = 2000, .max_command_output_bytes = 64 * 1024, .max_tool_result_bytes = 64 * 1024, .api_key = "key", .agent_stream_provider = self.agent_stream_provider, .model = "anthropic/claude-opus-4.6", .gateway_retry_count = 1, .gateway_chat_url = "https://example.invalid", .agent_step_limit = 8, .tool_registry = .{ .tools = vision_agent_test_tools[0..] }, .permission_mode = .ask, .permission_grants = &.{}, .permission_rules = .{}, .worker = &self.worker, .session = &self.session, .session_allocator = self.alloc, .context_limits = .{ .image_adapter_output_bytes = .{ .value = .{ .bytes = 64 * 1024 }, .source = .command_line, } }, .context_registry = .{ .default_provider = builtin_context.provider }, .lifecycle_scope = .{ .kind = .interactive, .workspace_root = self.workspace_root, .session_id = self.session_id, }, .output_chunk_ctx = undefined, .on_output_chunk = discardVisionToolOutput, }; }};
fn discardVisionToolOutput( _: *anyopaque, _: ?types.ToolLifecycleId, _: command_output_content.Stream, _: []const u8,) anyerror!void {}
const test_tools = [_]tool_dispatch.Tool{ builtin_tools.glob_files, builtin_tools.grep_files, builtin_tools.read_file, builtin_tools.write_file, builtin_tools.edit_file, builtin_tools.web_fetch, builtin_tools.web_search, builtin_tools.shell, builtin_tools.capability_search, builtin_tools.skill, builtin_tools.install_skill, builtin_tools.subagent, builtin_tools.mcp_select_tool, builtin_tools.ask_user_question, builtin_tools.read_tool_result,};const test_tool_registry = tool_dispatch.Registry{ .tools = test_tools[0..] };
fn testExecutionAuthority(call: ToolCall) command_admission.ToolExecutionAuthority { if (!std.mem.eql(u8, call.name, "shell")) return .ordinary; if (std.mem.find(u8, call.arguments_json, "\"action\":\"run\"") == null) { return .ordinary; } return .{ .run_command = .{ .shell_allowed = .{ .fingerprint = .{ .command = call.arguments_json, .resolved_cwd = "", .target_os = builtin.os.tag, }, .source = .interactive_once, } } };}
pub const FakeCompletion = struct { status: std.http.Status = .ok, err_body: ?[]const u8 = null, failure_schema: ?[]const u8 = null, failure_request_shape: ?[]const u8 = null, retry_after_seconds: ?u64 = null, pre_admission_error: ?anyerror = null, pre_send_error: ?anyerror = null, stream_error: ?anyerror = null, stream_error_after_chunks: ?anyerror = null, stream_error_after_tool_starts: ?anyerror = null, chunks: []const []const u8 = &.{}, reasoning_chunks: []const []const u8 = &.{}, content: ?[]const u8 = null, provider_state_json: ?[]const u8 = null, tool_calls: []const ToolCall = &.{}, streamed_tool_starts: []const ToolCall = &.{}, provider_result_identity_failure: ?types.ProviderResultIdentityFailure = null, provider_failure_cause: ?types.ProviderFailureCause = null, provider_failure_detail: ?[]const u8 = null, finish_reason: ?types.ProviderFinishReason = null, omit_finish: bool = false, usage: types.Usage = .{}, generation_id: ?[]const u8 = null, billing: ?types.ProviderBilling = null, exact_usage_provider: ?model_provider.ProviderId = null, delivery_ambiguous: bool = false, pause_before_output: bool = false, cancel_before_output: bool = false, cancel_after_chunks: bool = false, cancel_during_tool_stream: bool = false,};
pub const FakeGateway = struct { alloc: Allocator, completions: []const FakeCompletion, index: usize = 0, request_bodies: std.ArrayList([]u8) = .empty, request_models: std.ArrayList([]u8) = .empty, request_api_keys: std.ArrayList([]u8) = .empty, request_session_ids: std.ArrayList(?[]u8) = .empty, admitted_requests: usize = 0, recovery_pause_flag: ?*std.atomic.Value(bool) = null, observe_request: ?*const fn (agent_stream_provider.ModelRequest) anyerror!void = null,
pub fn init(alloc: Allocator, completions: []const FakeCompletion) FakeGateway { return .{ .alloc = alloc, .completions = completions }; }
pub fn deinit(self: *FakeGateway) void { for (self.request_bodies.items) |body| self.alloc.free(body); self.request_bodies.deinit(self.alloc); for (self.request_models.items) |model| self.alloc.free(model); self.request_models.deinit(self.alloc); for (self.request_api_keys.items) |api_key| self.alloc.free(api_key); self.request_api_keys.deinit(self.alloc); for (self.request_session_ids.items) |session_id| { if (session_id) |id| self.alloc.free(id); } self.request_session_ids.deinit(self.alloc); }
pub fn provider(self: *FakeGateway) agent_stream_provider.Provider { var result = builtin_gateway.agent_stream_provider; result.context = self; result.stream_fn = fakeGatewayStream; return result; }
fn stream( self: *FakeGateway, alloc: Allocator, request: agent_stream_provider.ModelRequest, ) !agent_stream_provider.Result { if (self.observe_request) |observe| try observe(request); const payload = request.prepared_request_body orelse try builtin_gateway.buildAgentRequest(alloc, request.data()); defer if (request.prepared_request_body == null) alloc.free(payload); try self.request_bodies.append(self.alloc, try self.alloc.dupe(u8, payload)); try self.request_models.append(self.alloc, try self.alloc.dupe(u8, request.model)); try self.request_api_keys.append(self.alloc, try self.alloc.dupe(u8, request.credential.secret() orelse "")); const session_id = if (request.session_id) |id| try self.alloc.dupe(u8, id) else null; errdefer if (session_id) |id| self.alloc.free(id); try self.request_session_ids.append(self.alloc, session_id); if (self.index >= self.completions.len) return error.TestUnexpectedGatewayRequest; const completion = self.completions[self.index]; self.index += 1; if (completion.pre_admission_error) |err| return err; try request.admission.admit(); self.admitted_requests += 1;
if (completion.pre_send_error) |err| { recordNetworkFailureEvidence(request, err); return err; } request.delivery.markPossiblySent();
if (completion.stream_error) |err| { recordNetworkFailureEvidence(request, err); return err; }
if (completion.pause_before_output) { if (self.recovery_pause_flag) |flag| flag.store(true, .seq_cst); request.cancel_flag.store(true, .seq_cst); return error.Cancelled; } if (completion.cancel_before_output) { request.cancel_flag.store(true, .seq_cst); return .{ .completed = .{} }; }
for (completion.reasoning_chunks) |chunk| request.events.emit(.{ .reasoning_delta = chunk }); for (completion.chunks) |chunk| { request.events.emit(.{ .content_delta = chunk }); } if (completion.cancel_after_chunks) request.cancel_flag.store(true, .seq_cst); if (completion.stream_error_after_chunks) |err| { recordNetworkFailureEvidence(request, err); return err; } for (completion.streamed_tool_starts) |call| { request.events.emit(.{ .tool_started = .{ .id = call.id, .name = call.name } }); } if (completion.stream_error_after_tool_starts) |err| { recordNetworkFailureEvidence(request, err); return err; } if (completion.cancel_during_tool_stream) { request.cancel_flag.store(true, .seq_cst); return error.Cancelled; } if (completion.status != .ok) { const err_body = if (completion.err_body) |body| try alloc.dupe(u8, body) else null; errdefer if (err_body) |value| alloc.free(value); const failure_schema = if (completion.failure_schema) |value| try alloc.dupe(u8, value) else null; errdefer if (failure_schema) |value| alloc.free(value); const failure_request_shape = if (completion.failure_request_shape) |value| try alloc.dupe(u8, value) else null; return .{ .failed = .{ .kind = failureKind(completion.status), .detail = err_body, .retry_after_seconds = completion.retry_after_seconds, .diagnostics = .{ .schema = failure_schema, .request_shape = failure_request_shape, }, .ownership = .owned, } }; }
return .{ .completed = .{ .completion = .{ .content = completion.content, .provider_state_json = completion.provider_state_json, .tool_calls = completion.tool_calls, .provider_result_identity_failure = completion.provider_result_identity_failure, .provider_failure_cause = completion.provider_failure_cause, .provider_failure_detail = completion.provider_failure_detail, .delivery_ambiguous = completion.delivery_ambiguous, .finish_reason = if (completion.omit_finish) null else completion.finish_reason orelse if (completion.tool_calls.len > 0) .tool_calls else .stop, .usage = completion.usage, .generation_id = completion.generation_id, .billing = completion.billing, }, .usage = if (completion.exact_usage_provider) |provider_id| .{ .exact = provider_id } else .{ .unavailable = .possibly_billed }, } }; }
fn recordNetworkFailureEvidence( request: agent_stream_provider.ModelRequest, err: anyerror, ) void { const cause: agent_stream_provider.NetworkFailureCause = if (err == error.SystemResumed) .system_resumed else if (err == error.TlsInitializationFailed or err == error.ConnectionSetupTimedOut or err == error.UnknownHostName or err == error.NameServerFailure or err == error.NoAddressReturned or err == error.DetectingNetworkConfigurationFailed or err == error.AddressUnavailable or err == error.ConnectionPending or err == error.ConnectionRefused or err == error.HostUnreachable or err == error.NetworkUnreachable or err == error.NetworkDown or err == error.WouldBlock or err == error.WriteFailed or err == error.ReadFailed or err == error.HttpConnectionClosing or err == error.ConnectionResetByPeer or err == error.ConnectionTimedOut or err == error.Timeout) .transport_interrupted else return; request.attempt_evidence.network_failure = .{ .cause = cause, .delivery = request.delivery.load(), }; }
fn failureKind(status: std.http.Status) agent_stream_provider.FailureKind { return switch (status) { .bad_request => .invalid_request, .unauthorized => .unauthorized, .forbidden => .forbidden, .payload_too_large => .request_too_large, .too_many_requests => .rate_limited, .internal_server_error => .server_error, .bad_gateway => .bad_gateway, .service_unavailable => .unavailable, .gateway_timeout => .gateway_timeout, else => .provider_error, }; }};
pub const ModelCapabilityOverride = struct { model: []const u8, capabilities: model_capabilities.Capabilities,};
fn fakeGatewayStream( context: ?*anyopaque, alloc: Allocator, request: agent_stream_provider.ModelRequest,) !agent_stream_provider.Result { const gateway: *FakeGateway = @ptrCast(@alignCast(context.?)); return gateway.stream(alloc, request);}
pub const FakeExecPlan = union(enum) { result: ToolExecutionResult, err: anyerror,};
pub const ExecuteDelegate = struct { ctx: *anyopaque, run: *const fn (*anyopaque, ToolExecutionRequest) anyerror!ToolExecutionResult, set_agent_stream_provider: ?*const fn (*anyopaque, agent_stream_provider.Provider) void = null,};
pub const PermissionRequestOverride = struct { context: *anyopaque, request_fn: *const fn ( *anyopaque, Allocator, ToolCall, permission_auto_classifier.ReviewTurnContext, PermissionMode, []const PermissionGrant, ?runtime_tool_contracts.LiveToolAuthority, ?runtime_tool_contracts.LivePermissionRevalidation, []const []const u8, ) anyerror!command_admission.PermissionOutcome,};
pub const ToolExecutionOverride = struct { context: *anyopaque, execute_fn: *const fn ( *anyopaque, ToolExecutionRequest, ) anyerror!ToolExecutionResult,};
fn captureReviewAuthority( alloc: Allocator, review_turn: permission_auto_classifier.ReviewTurnContext,) ![]u8 { var captured: std.ArrayList(u8) = .empty; errdefer captured.deinit(alloc); if (review_turn.trusted_root_context.len > 0) { try captured.appendSlice(alloc, review_turn.trusted_root_context); if (!std.mem.endsWith(u8, review_turn.trusted_root_context, "\n")) { try captured.append(alloc, '\n'); } } return captured.toOwnedSlice(alloc);}
pub const FakeAgentRuntimeDeps = struct { alloc: Allocator, agent_stream_provider: agent_stream_provider.Provider = agent_stream_provider.unavailable_provider, live_tool_authority: ?runtime_deps.LiveToolAuthorityProvider = null, tool_activity_recorder: ?runtime_deps.ToolActivityRecorder = null, tool_registry: tool_dispatch.Registry = test_tool_registry, context_registry: ?context_contract.Registry = null, context_enabled: bool = false, root_permission_mode: ?PermissionMode = null, validation_mcp_runtime_generation: ?u64 = null, validation_mcp_tool_name: ?[]const u8 = null, execute_mutex: std.Io.Mutex = .init, log: std.ArrayList([]u8) = .empty, texts: std.ArrayList([]u8) = .empty, assistant_sources: std.ArrayList([]u8) = .empty, system_notices: std.ArrayList([]u8) = .empty, interactive_notices: std.ArrayList(types.SemanticNotice) = .empty, context_notices: std.ArrayList([]u8) = .empty, route_recovery_statuses: std.ArrayList(types.RouteRecoveryStatus) = .empty, permission_names: std.ArrayList([]u8) = .empty, permission_call_ids: std.ArrayList([]u8) = .empty, permission_user_intent_contexts: std.ArrayList([]u8) = .empty, permission_review_models: std.ArrayList([]u8) = .empty, permission_review_target_call_ids: std.ArrayList([]u8) = .empty, permission_review_origins: std.ArrayList(permission_auto_classifier.ReviewOrigin) = .empty, permission_review_root_authority_counts: std.ArrayList(usize) = .empty, permission_review_feedback_counts: std.ArrayList(usize) = .empty, permission_review_pending_call_counts: std.ArrayList(usize) = .empty, executed_names: std.ArrayList([]u8) = .empty, executed_call_ids: std.ArrayList([]u8) = .empty, rejected_names: std.ArrayList([]u8) = .empty, failed_names: std.ArrayList([]u8) = .empty, inner_usage_names: std.ArrayList([]u8) = .empty, inner_usages: std.ArrayList(types.ToolUsage) = .empty, validated_names: std.ArrayList([]u8) = .empty, availability_checked_names: std.ArrayList([]u8) = .empty, execution_classification_complete: std.ArrayList(bool) = .empty, execution_mcp_runtime_generations: std.ArrayList(?u64) = .empty, last_validated_arguments: ?[]u8 = null, last_permission_arguments: ?[]u8 = null, last_executed_arguments: ?[]u8 = null, last_permission_credential: ?[]u8 = null, last_execute_credential: ?[]u8 = null, last_execute_root_user_intent_context: ?[]u8 = null, last_execute_root_user_messages: std.ArrayList([]u8) = .empty, last_execute_root_user_evidence_complete: bool = false, last_execute_permission_mode: ?PermissionMode = null, propagated_grants: std.ArrayList(PermissionGrant) = .empty, event_grants: std.ArrayList(PermissionGrant) = .empty, last_execute_grants: std.ArrayList(PermissionGrant) = .empty, last_live_authority_generation: ?u64 = null, last_live_authority_tool_count: usize = 0, last_live_authority_integration_count: usize = 0, last_live_authority_rule_count: usize = 0, last_live_authority_grant_count: usize = 0, last_frozen_file_grants: std.ArrayList(PermissionGrant) = .empty, permission_decisions: []const ToolPermissionDecision = &.{}, permission_auto_review_results: []const ?permission_auto_classifier.Result = &.{}, permission_denial_reasons: []const types.ToolPermissionDenialReason = &.{}, permission_feedback: []const []const u8 = &.{}, permission_errors: []const ?anyerror = &.{}, permission_human_approvals: []const command_admission.HumanApprovalProvenance = &.{}, permission_request_override: ?PermissionRequestOverride = null, permission_wait_index: ?usize = null, permission_waiting: ?*std.atomic.Value(bool) = null, permission_release: ?*std.atomic.Value(bool) = null, tool_execution_override: ?ToolExecutionOverride = null, catalog_unavailable: bool = false, permission_failure_names: []const []const u8 = &.{}, permission_index: usize = 0, exec_plans: []const FakeExecPlan = &.{}, execute_delegate: ?ExecuteDelegate = null, exec_index: usize = 0, successful_effect_count: std.atomic.Value(usize) = std.atomic.Value(usize).init(0), execute_timeout_started_ms: std.ArrayList(?i64) = .empty, permission_target: []const u8 = "/tmp/workspace/file.txt", resolve_permission_target: bool = false, tool_display_target: ?[]const u8 = null, tool_display_target_after_execute: ?[]const u8 = null, tool_display_target_resolve_count: usize = 0, swap_link_on_permission: ?[]const u8 = null, swap_link_target_on_permission: ?[]const u8 = null, swap_link_on_execute_name: ?[]const u8 = null, swap_link_on_execute: ?[]const u8 = null, swap_link_target_on_execute: ?[]const u8 = null, static_context_text: ?[]const u8 = null, parent_turn_context_text: ?[]const u8 = null, parent_turn_context_texts: []const []const u8 = &.{}, parent_turn_context_index: usize = 0, parent_turn_context_after_execute: ?[]const u8 = null, parent_turn_context_sequence: ?u64 = null, parent_turn_prepare_count: usize = 0, parent_turn_ack_count: usize = 0, parent_turn_last_ack_sequence: u64 = 0, parent_turn_last_ack_prepare_count: usize = 0, parent_turn_ack_contract_valid: bool = true, runtime_context_text: ?[]const u8 = null, runtime_context_texts: []const []const u8 = &.{}, runtime_context_index: usize = 0, runtime_context_error: ?anyerror = null, last_execute_grant_count: usize = 0, command_complete_count: usize = 0, route_recovery_clear_count: usize = 0, full_detail_records: std.ArrayList(types.SemanticNotice) = .empty, finish_event_count: usize = 0, finish_event_attempt_count: usize = 0, finish_event_error: ?anyerror = null, finalization_count: usize = 0, finalized_turn_id: u64 = 0, finalized_outcome: ?types.TurnPresentationOutcome = null, finalized_disposition: ?types.ProviderCompletionDisposition = null, finalization_error: ?anyerror = null, terminal_lease_cleanup_ids: std.ArrayList([]u8) = .empty, terminal_lease_cleanup_errors: []const ?anyerror = &.{}, terminal_lease_cleanup_index: usize = 0, finish_assistant_text: ?[]u8 = null, finish_presentation_text: ?[]u8 = null, finish_summary: ?types.TurnSummary = null, finish_projection: ?types.FinishedPromptProjection = null, finish_terminal_outcome: ?types.TurnPresentationOutcome = null, history_assistant_text: ?[]u8 = null, history_propagation_count: usize = 0, history_propagation_error: ?anyerror = null, background_history_log_path: ?[]u8 = null, background_event_log_path: ?[]u8 = null, history_turns: std.ArrayList(HistoryTurn) = .empty, compaction_prefixes: std.ArrayList(?HistoryTurn) = .empty, interrupted_history_count: usize = 0, interrupted_event_count: usize = 0, interrupted_tool_name: ?[]u8 = null, http_status: ?std.http.Status = null, http_detail: ?[]u8 = null, http_credential_source: ?types.CredentialSource = null, diff_count: usize = 0, diff_preview: ?[]u8 = null, token_updates: std.ArrayList(types.TurnTokenProgress) = .empty, lifecycle_events: std.ArrayList(types.ToolLifecycleEvent) = .empty, cancel_on_text: ?*std.atomic.Value(bool) = null, cancel_on_text_match: ?[]const u8 = null, cancel_on_auto_retry_status: ?*std.atomic.Value(bool) = null, cancel_on_auto_retry_attempt: ?usize = null, cancel_on_permission: ?*std.atomic.Value(bool) = null, cancel_on_permission_name: ?[]const u8 = null, cancel_on_execute: ?*std.atomic.Value(bool) = null, cancel_on_execute_name: ?[]const u8 = null, cancel_on_execute_index: ?usize = null, cancel_on_execute_delay_ms: u64 = 0, ordinary_cancel_on_execute_name: ?[]const u8 = null, session_context: ?*session_runtime.SessionRuntime = null, usage: ?*session_usage.Usage = null, validation_not_registered_names: []const []const u8 = &.{}, validation_failure_names: []const []const u8 = &.{}, validation_results: []const ?[]const u8 = &.{}, validation_result_index: usize = 0, validation_error: ?anyerror = null, availability_failure_names: []const []const u8 = &.{}, workspace_root: []const u8 = "/tmp/workspace", committed_publication_report: SecondaryPublicationReport = .{ .diff = .published, .tracker = .published, }, stream_output_token_error: ?anyerror = null, fail_status_finished: bool = false, command_replay_output: ?[]const u8 = null, command_replay_capability: ?*session_child_store.SessionChildCapability = null, last_file_request_allocators_distinct: bool = false, route_recovery_decisions: []const runtime_deps.RouteRecoveryDecision = &.{}, enable_route_recovery: bool = true, route_recovery_index: usize = 0, route_recovery_count: usize = 0, last_route_recovery_replay_safe: bool = false, last_route_recovery_fast_mode: bool = false, last_route_recovery_finish_reason: ?types.ProviderFinishReason = null, last_route_recovery_unsafe_reason: ?types.RouteRecoveryUnsafeReason = null, default_model_capabilities: model_capabilities.Capabilities = .{ .image_input_support = .non_native, .context_window = 1_000_000, }, capability_overrides: []const ModelCapabilityOverride = &.{}, available_capability_overrides: []const ModelCapabilityOverride = &.{}, capability_queries: std.ArrayList([]u8) = .empty, cancel_on_capability_resolution: ?*std.atomic.Value(bool) = null, cancel_after_capability_resolution: ?*std.atomic.Value(bool) = null, credential_refresh_tokens: []const []const u8 = &.{}, credential_refresh_index: usize = 0, credential_refresh_sources: std.ArrayList(types.CredentialSource) = .empty, credential_refresh_modes: std.ArrayList(runtime_deps.CredentialRefreshMode) = .empty, credential_refresh_error: ?anyerror = null, last_credential_refresh_expected_account: ?[]u8 = null, enable_interactive_notices: bool = false, enable_recovery_checkpoint: bool = false, recovery_checkpoints: std.ArrayList(session_codec.RecoveryCheckpoint) = .empty, recovery_checkpoint_error: ?anyerror = null, recovery_checkpoint_error_at: ?usize = null, recovery_checkpoint_calls: usize = 0, recovery_checkpoint_clears: usize = 0, cancel_on_recovery_reservation: ?*std.atomic.Value(bool) = null, pause_on_auto_retry_status: bool = false, pause_on_auto_retry_attempt: ?usize = null, recovery_pause_flag: ?*std.atomic.Value(bool) = null, route_recovery_status_error_attempt: ?usize = null, steering_messages: []const []const u8 = &.{}, steering_take_at: usize = 1, steering_take_count: usize = 0, immediate_steering_messages: []const []const u8 = &.{}, immediate_steering_cancel_flag: ?*std.atomic.Value(bool) = null, immediate_steering_take_count: usize = 0,
pub fn init(alloc: Allocator) FakeAgentRuntimeDeps { return .{ .alloc = alloc }; }
pub fn deinit(self: *FakeAgentRuntimeDeps) void { freeStringList(self.alloc, &self.log); freeStringList(self.alloc, &self.texts); freeStringList(self.alloc, &self.assistant_sources); freeStringList(self.alloc, &self.system_notices); for (self.interactive_notices.items) |notice| types.freeSemanticNotice(self.alloc, notice); self.interactive_notices.deinit(self.alloc); for (self.full_detail_records.items) |notice| types.freeSemanticNotice(self.alloc, notice); self.full_detail_records.deinit(self.alloc); freeStringList(self.alloc, &self.context_notices); self.route_recovery_statuses.deinit(self.alloc); freeStringList(self.alloc, &self.permission_names); freeStringList(self.alloc, &self.permission_call_ids); freeStringList(self.alloc, &self.permission_user_intent_contexts); freeStringList(self.alloc, &self.permission_review_models); freeStringList(self.alloc, &self.permission_review_target_call_ids); self.permission_review_origins.deinit(self.alloc); self.permission_review_root_authority_counts.deinit(self.alloc); self.permission_review_feedback_counts.deinit(self.alloc); self.permission_review_pending_call_counts.deinit(self.alloc); freeStringList(self.alloc, &self.executed_names); freeStringList(self.alloc, &self.executed_call_ids); freeStringList(self.alloc, &self.rejected_names); freeStringList(self.alloc, &self.failed_names); freeStringList(self.alloc, &self.inner_usage_names); self.inner_usages.deinit(self.alloc); freeStringList(self.alloc, &self.validated_names); freeStringList(self.alloc, &self.availability_checked_names); self.execution_classification_complete.deinit(self.alloc); self.execution_mcp_runtime_generations.deinit(self.alloc); if (self.last_validated_arguments) |value| self.alloc.free(value); if (self.last_permission_arguments) |value| self.alloc.free(value); if (self.last_executed_arguments) |value| self.alloc.free(value); if (self.last_permission_credential) |value| self.alloc.free(value); if (self.last_execute_credential) |value| self.alloc.free(value); if (self.last_execute_root_user_intent_context) |value| self.alloc.free(value); freeStringList(self.alloc, &self.last_execute_root_user_messages); freeGrantList(self.alloc, &self.propagated_grants); freeGrantList(self.alloc, &self.event_grants); freeGrantList(self.alloc, &self.last_execute_grants); freeGrantList(self.alloc, &self.last_frozen_file_grants); self.execute_timeout_started_ms.deinit(self.alloc); if (self.finish_assistant_text) |value| self.alloc.free(value); if (self.finish_presentation_text) |value| self.alloc.free(value); freeStringList(self.alloc, &self.terminal_lease_cleanup_ids); if (self.history_assistant_text) |value| self.alloc.free(value); if (self.background_history_log_path) |value| self.alloc.free(value); if (self.background_event_log_path) |value| self.alloc.free(value); for (self.history_turns.items) |turn| types.freeHistoryTurn(self.alloc, turn); self.history_turns.deinit(self.alloc); for (self.compaction_prefixes.items) |prefix| if (prefix) |turn| types.freeHistoryTurn(self.alloc, turn); self.compaction_prefixes.deinit(self.alloc); if (self.interrupted_tool_name) |value| self.alloc.free(value); if (self.http_detail) |value| self.alloc.free(value); if (self.diff_preview) |value| self.alloc.free(value); self.token_updates.deinit(self.alloc); for (self.lifecycle_events.items) |event| { worker_runtime.freeToolLifecycleEvent(self.alloc, event); } self.lifecycle_events.deinit(self.alloc); freeStringList(self.alloc, &self.capability_queries); self.credential_refresh_sources.deinit(self.alloc); self.credential_refresh_modes.deinit(self.alloc); if (self.last_credential_refresh_expected_account) |value| self.alloc.free(value); for (self.recovery_checkpoints.items) |*checkpoint| checkpoint.deinit(self.alloc); self.recovery_checkpoints.deinit(self.alloc); }
pub fn deps(self: *FakeAgentRuntimeDeps) AgentRuntimeDeps { return .{ .ctx = self, .agent_stream_provider = self.agent_stream_provider, .tool_registry = self.tool_registry, .live_tool_authority = self.live_tool_authority, .tool_activity_recorder = self.tool_activity_recorder, .context_registry = self.context_registry, .context_enabled = self.context_enabled, .snapshot_root_permission_mode = if (self.root_permission_mode != null) snapshotRootPermissionMode else null, .finalize_turn = finalizeTurn, .release_agent_terminal_lease = releaseAgentTerminalLease, .prepare_parent_turn_context = prepareParentTurnContext, .acknowledge_parent_turn_context = acknowledgeParentTurnContext, .append_runtime_context = appendRuntimeContext, .append_static_context = appendStaticContext, .validate_tool_call = validateToolCall, .check_tool_availability = checkToolAvailability, .request_tool_permission = requestPermission, .resolve_tool_action_display_target = resolveToolActionDisplayTarget, .describe_tool_action = describeAction, .describe_tool_action_completed = describeCompleted, .describe_tool_action_denied = describeDenied, .permission_target_for_call = permissionTarget, .execute_tool_call = execute, .publish_committed_file_handoff = publishCommittedFileHandoff, .propagate_history_turn = propagateHistory, .commit_context_compaction = .{ .commit = commitCompaction }, .recovery_checkpoint = if (self.enable_recovery_checkpoint) .{ .set = setRecoveryCheckpoint, .clear = clearRecoveryCheckpoint, } else null, .propagate_grant = @This().propagateGrant, .push_event = pushEvent, .push_text = pushText, .push_tool_lifecycle = pushToolLifecycle, .push_diff_block = pushDiff, .push_system_notice = systemNotice, .push_interactive_notice = if (self.enable_interactive_notices) interactiveNotice else null, .push_context_notice = contextNotice, .push_route_recovery_status = routeRecoveryStatus, .push_command_output_complete = commandOutputComplete, .push_http_error = httpError, .refresh_gateway_credential = refreshGatewayCredential, .request_route_recovery = if (self.enable_route_recovery) requestRouteRecovery else null, .available_model_capabilities = availableModelCapabilities, .resolve_model_capabilities = resolveModelCapabilities, .model_catalog_unavailable = catalogUnavailable, .take_steering_boundary = if (self.steering_messages.len > 0 or self.immediate_steering_messages.len > 0) takeSteeringBoundary else null, .format_tool_execution_error = formatError, .record_tool_call_rejected = recordRejected, .record_tool_call_failed = recordFailed, .report_inner_tool_usage = reportCapturedInnerToolUsage, .usage = self.usage, .usage_allocator = self.alloc, }; }
fn clearRecoveryCheckpoint(raw: *anyopaque) !void { const self: *FakeAgentRuntimeDeps = @ptrCast(@alignCast(raw)); self.recovery_checkpoint_clears += 1; }
fn setRecoveryCheckpoint( raw: *anyopaque, checkpoint: session_codec.RecoveryCheckpoint, ) !void { const self: *FakeAgentRuntimeDeps = @ptrCast(@alignCast(raw)); self.recovery_checkpoint_calls += 1; if (self.recovery_checkpoint_error) |err| { if (self.recovery_checkpoint_error_at == null or self.recovery_checkpoint_error_at.? == self.recovery_checkpoint_calls) { return err; } } try self.recovery_checkpoints.append( self.alloc, try checkpoint.dupe(self.alloc), ); if (checkpoint.outstanding_reservation) { if (self.cancel_on_recovery_reservation) |cancel_flag| { cancel_flag.store(true, .seq_cst); } } }
fn snapshotRootPermissionMode(raw: *anyopaque) PermissionMode { const self: *FakeAgentRuntimeDeps = @ptrCast(@alignCast(raw)); return self.root_permission_mode.?; }
fn catalogUnavailable(raw: *anyopaque) bool { const self: *FakeAgentRuntimeDeps = @ptrCast(@alignCast(raw)); return self.catalog_unavailable; }
fn resolveModelCapabilities(raw: *anyopaque, _: Allocator, model: []const u8) !model_capabilities.Capabilities { const self: *FakeAgentRuntimeDeps = @ptrCast(@alignCast(raw)); try self.capability_queries.append(self.alloc, try self.alloc.dupe(u8, model)); if (self.cancel_on_capability_resolution) |cancel_flag| { cancel_flag.store(true, .seq_cst); return error.Cancelled; } const capabilities = blk: { for (self.capability_overrides) |override| { if (std.mem.eql(u8, override.model, model)) break :blk override.capabilities; } break :blk self.default_model_capabilities; }; if (self.cancel_after_capability_resolution) |cancel_flag| { cancel_flag.store(true, .seq_cst); } return capabilities; }
fn availableModelCapabilities(raw: *anyopaque, model: []const u8) model_capabilities.Capabilities { const self: *FakeAgentRuntimeDeps = @ptrCast(@alignCast(raw)); for (self.available_capability_overrides) |override| { if (std.mem.eql(u8, override.model, model)) return override.capabilities; } return self.default_model_capabilities; }
fn refreshGatewayCredential(raw: *anyopaque, alloc: Allocator, source: types.CredentialSource, mode: runtime_deps.CredentialRefreshMode, expected_account_id: ?[]const u8) !?[]u8 { const self: *FakeAgentRuntimeDeps = @ptrCast(@alignCast(raw)); try self.credential_refresh_sources.append(self.alloc, source); try self.credential_refresh_modes.append(self.alloc, mode); if (self.last_credential_refresh_expected_account) |value| self.alloc.free(value); self.last_credential_refresh_expected_account = if (expected_account_id) |account_id| try self.alloc.dupe(u8, account_id) else null; if (self.credential_refresh_error) |err| return err; if (self.credential_refresh_index >= self.credential_refresh_tokens.len) return null; const token = self.credential_refresh_tokens[self.credential_refresh_index]; self.credential_refresh_index += 1; return try alloc.dupe(u8, token); }
fn takeSteeringBoundary( raw: *anyopaque, arena: Allocator, _: u64, kind: worker_runtime.SteeringBoundaryKind, ) !worker_runtime.SteeringBoundaryResult { const self: *FakeAgentRuntimeDeps = @ptrCast(@alignCast(raw)); const source = switch (kind) { .model, .finalizing => blk: { self.steering_take_count += 1; if (self.steering_take_count != self.steering_take_at) return .none; break :blk self.steering_messages; }, .cancelled => blk: { self.immediate_steering_take_count += 1; if (self.immediate_steering_take_count != 1) return .interrupt; if (self.immediate_steering_cancel_flag) |flag| flag.store(false, .seq_cst); break :blk self.immediate_steering_messages; }, }; if (source.len == 0) return if (kind == .cancelled) .interrupt else .none; const messages = try arena.alloc([]u8, source.len); for (source, messages) |text, *copy| copy.* = try arena.dupe(u8, text); return .{ .continue_turn = messages }; }
fn requestRouteRecovery(raw: *anyopaque, _: Allocator, request: runtime_deps.RouteRecoveryRequest) !runtime_deps.RouteRecoveryDecision { const self: *FakeAgentRuntimeDeps = @ptrCast(@alignCast(raw)); self.route_recovery_count += 1; self.last_route_recovery_replay_safe = request.replay_safe; self.last_route_recovery_fast_mode = request.fast_mode; self.last_route_recovery_finish_reason = request.finish_reason; self.last_route_recovery_unsafe_reason = request.unsafe_no_retry_reason; if (self.route_recovery_index < self.route_recovery_decisions.len) { const decision = self.route_recovery_decisions[self.route_recovery_index]; self.route_recovery_index += 1; return decision; } return .cancel; }
fn finalizeTurn(raw: *anyopaque, turn_id: u64, outcome: types.TurnPresentationOutcome, disposition: ?types.ProviderCompletionDisposition) !void { const self: *FakeAgentRuntimeDeps = @ptrCast(@alignCast(raw)); self.finalization_count += 1; self.finalized_turn_id = turn_id; self.finalized_outcome = outcome; self.finalized_disposition = disposition; try self.record("event:turn_finished", .{}); if (self.finalization_error) |err| return err; }
fn releaseAgentTerminalLease(raw: *anyopaque, session_id: []const u8) !void { const self: *FakeAgentRuntimeDeps = @ptrCast(@alignCast(raw)); try self.terminal_lease_cleanup_ids.append( self.alloc, try self.alloc.dupe(u8, session_id), ); const index = self.terminal_lease_cleanup_index; self.terminal_lease_cleanup_index += 1; if (index < self.terminal_lease_cleanup_errors.len) { if (self.terminal_lease_cleanup_errors[index]) |err| return err; } }
fn appendStaticContext(raw: *anyopaque, arena: Allocator, project_context: ?[]const u8, messages: *std.ArrayList(ChatMessage)) !void { const self: *FakeAgentRuntimeDeps = @ptrCast(@alignCast(raw)); if (project_context orelse self.static_context_text) |text| { try messages.append(arena, .{ .role = .system, .content = try arena.dupe(u8, text) }); } }
fn record(self: *FakeAgentRuntimeDeps, comptime fmt: []const u8, args: anytype) !void { try self.log.append(self.alloc, try std.fmt.allocPrint(self.alloc, fmt, args)); }
fn prepareParentTurnContext(raw: *anyopaque, arena: Allocator) !?runtime_deps.PreparedParentTurnContext { const self: *FakeAgentRuntimeDeps = @ptrCast(@alignCast(raw)); self.parent_turn_prepare_count += 1; const text = if (self.parent_turn_context_texts.len > 0) blk: { const index = @min(self.parent_turn_context_index, self.parent_turn_context_texts.len - 1); self.parent_turn_context_index += 1; break :blk self.parent_turn_context_texts[index]; } else self.parent_turn_context_text orelse return null; const acknowledgements = try arena.alloc(runtime_deps.ParentTurnDeliveryAck, 1); acknowledgements[0] = .{ .child_id = try arena.dupe(u8, "child"), .target_session_id = try arena.dupe(u8, "parent"), .through_sequence = self.parent_turn_context_sequence orelse @as(u64, @intCast(self.parent_turn_prepare_count)), .delivery_id = try arena.dupe(u8, "delivery"), .start_offset = 0, .total_bytes = 0, }; return .{ .content = try arena.dupe(u8, text), .acknowledgements = acknowledgements, }; }
fn acknowledgeParentTurnContext( raw: *anyopaque, _: Allocator, acknowledgements: []const runtime_deps.ParentTurnDeliveryAck, ) void { const self: *FakeAgentRuntimeDeps = @ptrCast(@alignCast(raw)); self.parent_turn_ack_count += acknowledgements.len; self.parent_turn_ack_contract_valid = self.parent_turn_ack_contract_valid and self.parent_turn_prepare_count == self.parent_turn_last_ack_prepare_count + 1; self.parent_turn_last_ack_prepare_count = self.parent_turn_prepare_count; for (acknowledgements) |ack| { self.parent_turn_ack_contract_valid = self.parent_turn_ack_contract_valid and std.mem.eql(u8, ack.child_id, "child") and std.mem.eql(u8, ack.target_session_id, "parent") and std.mem.eql(u8, ack.delivery_id, "delivery"); } if (acknowledgements.len != 0) { self.parent_turn_last_ack_sequence = acknowledgements[acknowledgements.len - 1].through_sequence; } }
fn appendRuntimeContext(raw: *anyopaque, arena: Allocator, messages: *std.ArrayList(ChatMessage)) !void { const self: *FakeAgentRuntimeDeps = @ptrCast(@alignCast(raw)); if (self.runtime_context_error) |err| return err; if (self.runtime_context_texts.len > 0) { const index = @min(self.runtime_context_index, self.runtime_context_texts.len - 1); const text = self.runtime_context_texts[index]; self.runtime_context_index += 1; try messages.append(arena, .{ .role = .system, .content = try arena.dupe(u8, text) }); } else if (self.runtime_context_text) |text| { try messages.append(arena, .{ .role = .system, .content = try arena.dupe(u8, text) }); } }
fn validateToolCall(raw: *anyopaque, arena: Allocator, call: ToolCall) !ToolCallValidationResult { const self: *FakeAgentRuntimeDeps = @ptrCast(@alignCast(raw)); try self.validated_names.append(self.alloc, try self.alloc.dupe(u8, call.name)); if (self.validation_error) |err| return err; if (self.last_validated_arguments) |value| self.alloc.free(value); self.last_validated_arguments = try self.alloc.dupe(u8, call.arguments_json); try self.record("validate:{s}", .{call.name}); if (self.validation_result_index < self.validation_results.len) { const result = self.validation_results[self.validation_result_index]; self.validation_result_index += 1; if (result) |failure| { return .{ .failure = try arena.dupe(u8, failure) }; } } for (self.validation_not_registered_names) |name| { if (std.mem.eql(u8, name, call.name)) return .not_registered; } for (self.validation_failure_names) |name| { if (std.mem.eql(u8, name, call.name)) { return .{ .failure = try std.fmt.allocPrint(arena, "{s} arguments failed registered-tool validation", .{call.name}) }; } } const mcp_runtime_generation = if (self.validation_mcp_tool_name) |name| if (std.mem.eql(u8, name, call.name)) self.validation_mcp_runtime_generation else null else null; return .{ .valid = .{ .mcp_runtime_generation = mcp_runtime_generation, } }; }
fn checkToolAvailability(raw: *anyopaque, arena: Allocator, call: ToolCall) !?[]const u8 { const self: *FakeAgentRuntimeDeps = @ptrCast(@alignCast(raw)); try self.availability_checked_names.append(self.alloc, try self.alloc.dupe(u8, call.name)); try self.record("availability:{s}", .{call.name}); for (self.availability_failure_names) |name| { if (std.mem.eql(u8, name, call.name)) { return try arena.dupe(u8, tool_dispatch.web_search_unavailable_message); } } return null; }
fn scriptedAutoReview( arena: Allocator, results: []const ?permission_auto_classifier.Result, index: usize, ) !?permission_auto_classifier.Result { if (index >= results.len) return null; const result = results[index] orelse return null; return permission_auto_classifier.Result{ .risk = result.risk, .decision = result.decision, .rationale = try arena.dupe(u8, result.rationale), }; }
fn requestPermission( raw: *anyopaque, arena: Allocator, call: ToolCall, review_turn: permission_auto_classifier.ReviewTurnContext, permission_mode: PermissionMode, local_grants: []const PermissionGrant, live_authority: ?runtime_tool_contracts.LiveToolAuthority, revalidation: ?runtime_tool_contracts.LivePermissionRevalidation, advertised_dynamic_tool_names: []const []const u8, _: ?[]const u8, ) !command_admission.PermissionOutcome { const self: *FakeAgentRuntimeDeps = @ptrCast(@alignCast(raw)); if (self.permission_request_override) |override| { return override.request_fn( override.context, arena, call, review_turn, permission_mode, local_grants, live_authority, revalidation, advertised_dynamic_tool_names, ); } try self.permission_names.append(self.alloc, try self.alloc.dupe(u8, call.name)); try self.permission_call_ids.append(self.alloc, try self.alloc.dupe(u8, call.id)); try self.permission_user_intent_contexts.append( self.alloc, try captureReviewAuthority(self.alloc, review_turn), ); try self.permission_review_models.append( self.alloc, try self.alloc.dupe(u8, review_turn.model), ); try self.permission_review_target_call_ids.append( self.alloc, try self.alloc.dupe(u8, review_turn.target_call_id), ); try self.permission_review_origins.append(self.alloc, review_turn.origin); try self.permission_review_root_authority_counts.append( self.alloc, @intFromBool(review_turn.trusted_root_context.len > 0), ); try self.permission_review_feedback_counts.append( self.alloc, 0, ); try self.permission_review_pending_call_counts.append( self.alloc, review_turn.pending_assistant.tool_calls.len, ); if (self.last_permission_credential) |value| self.alloc.free(value); self.last_permission_credential = try self.alloc.dupe( u8, review_turn.credential.secret() orelse "", ); if (self.last_permission_arguments) |value| self.alloc.free(value); self.last_permission_arguments = try self.alloc.dupe(u8, call.arguments_json); try self.record("permission:{s}", .{call.name}); for (self.permission_failure_names) |name| { if (std.mem.eql(u8, name, call.name)) { return .{ .tool_failure = try arena.dupe( u8, "permission preflight failed", ) }; } } const permission_index = self.permission_index; const decision = if (permission_index < self.permission_decisions.len) self.permission_decisions[permission_index] else ToolPermissionDecision.once; const feedback = if (permission_index < self.permission_feedback.len) self.permission_feedback[permission_index] else ""; const denial_reason = if (decision.isDenied() and permission_index < self.permission_denial_reasons.len) self.permission_denial_reasons[permission_index] else null; const auto_review_result = try scriptedAutoReview( arena, self.permission_auto_review_results, permission_index, ); self.permission_index += 1; if (self.permission_wait_index == permission_index) { if (self.permission_waiting) |waiting| waiting.store(true, .seq_cst); const release = self.permission_release orelse return error.PermissionPromptUnavailable; while (!release.load(.seq_cst)) { std.Thread.yield() catch std.atomic.spinLoopHint(); } } const execution_authority = if (decision.isDenied()) null else if (revalidation) |request| switch (request) { .action => |action| action.authority, } else if (file_mutation_contract.isToolName(call.name)) command_admission.ToolExecutionAuthority{ .file_mutation = try self.fileMutationAuthorization( arena, call, permission_mode, local_grants, ), } else if (try self.testVisionPathAuthority(arena, call)) |authority| command_admission.ToolExecutionAuthority{ .vision_paths = authority } else testExecutionAuthority(call); if (self.swap_link_on_permission) |link| { if (self.swap_link_target_on_permission) |target| { var cwd = std.Io.Dir.cwd(); cwd.deleteFile(io_mod.getIo(), link) catch {}; try cwd.symLink(io_mod.getIo(), target, link, .{ .is_directory = true }); self.swap_link_on_permission = null; self.swap_link_target_on_permission = null; } } if (self.cancel_on_permission) |flag| { const should_cancel = if (self.cancel_on_permission_name) |name| std.mem.eql(u8, name, call.name) else true; if (should_cancel) flag.store(true, .seq_cst); } if (permission_index < self.permission_errors.len) { if (self.permission_errors[permission_index]) |err| return err; } return .{ .decision = decision, .execution_authority = execution_authority, .human_approval = if (permission_index < self.permission_human_approvals.len) self.permission_human_approvals[permission_index] else if (decision == .once) .once else if (decision == .always) .always else .none, .denial_reason = denial_reason, .feedback = if (feedback.len == 0) null else try arena.dupe(u8, feedback), .auto_review_result = auto_review_result, }; }
fn testVisionPathAuthority( self: *FakeAgentRuntimeDeps, arena: Allocator, call: ToolCall, ) !?command_admission.VisionPathExecutionAuthority { if (!std.mem.eql(u8, call.name, "vision")) return null; const request = runtime_tool_contracts.vision.parse_vision_request( arena, call.arguments_json, ) catch return null; defer request.deinit(arena); if (request.paths() == null) return null;
var targets = try permissions.permissionTargetsForCall( arena, self.workspace_root, call, .none, ); defer targets.deinit(arena); const execution_targets = try arena.alloc( command_admission.VisionPathExecutionTarget, targets.items.len, ); for (targets.items, execution_targets) |target, *execution_target| { if (!std.mem.eql(u8, target.role, "image")) { return error.InvalidToolArguments; } var file = try std.Io.Dir.openFileAbsolute(io_mod.getIo(), target.path, .{ .allow_directory = false, .follow_symlinks = false, }); defer file.close(io_mod.getIo()); const stat = try file.stat(io_mod.getIo()); execution_target.* = .{ .canonical_path = try arena.dupe(u8, target.path), .identity = pathing.fileIdentity( try pathing.descriptorDevice(file.handle), stat, ), }; } return .{ .targets = execution_targets }; }
fn fileMutationAuthorization( self: *FakeAgentRuntimeDeps, arena: Allocator, call: ToolCall, permission_mode: PermissionMode, local_grants: []const PermissionGrant, ) !file_mutation_contract.FileExecutionAuthorization { const kind: file_mutation_contract.Kind = if (std.mem.eql(u8, call.name, "write_file")) .write else if (std.mem.eql(u8, call.name, "edit_file")) .edit else return error.InvalidToolArguments; const tool = switch (kind) { .write => &builtin_tools.write_file, .edit => &builtin_tools.edit_file, }; const decoded = try tool.decode( .{ .allocator = arena }, call.arguments_json, ); const input: file_mutation_contract.FileMutationInput = switch (decoded) { .failure => return error.InvalidToolArguments, .input => |tool_input| blk: { break :blk switch (kind) { .write => testing_write_file.takeFileMutationInput( tool_input, arena, ), .edit => testing_edit_file.takeFileMutationInput( tool_input, arena, ), }; }, }; const evaluated = try permissions.evaluateFileMutationTargets( arena, self.workspace_root, input, permission_mode, .{}, &.{}, local_grants, ); const policy_targets = switch (evaluated) { .evaluated => |targets| targets, .policy_denied, .target_resolution_failure => try syntheticFileMutationTargets( arena, self.permission_target, ), }; const authorization: file_mutation_contract.FileExecutionAuthorization = .{ .input = input, .policy_targets = policy_targets, .grant_offer = try permissions.structuredFileGrantOffer( arena, self.workspace_root, call.name, policy_targets, ), .approval_intent = .mutation, }; for (self.last_frozen_file_grants.items) |grant| { self.alloc.free(grant.tool_name); self.alloc.free(grant.target_path); } self.last_frozen_file_grants.clearRetainingCapacity(); for (authorization.grant_offer.?.grants) |grant| { try appendGrant( self.alloc, &self.last_frozen_file_grants, grant, ); } return authorization; }
fn resolveToolActionDisplayTarget(raw: *anyopaque, arena: Allocator, _: ToolCall) !?[]const u8 { const self: *FakeAgentRuntimeDeps = @ptrCast(@alignCast(raw)); self.tool_display_target_resolve_count += 1; const value = self.tool_display_target orelse return null; return try arena.dupe(u8, value); }
fn describeAction(_: *anyopaque, arena: Allocator, call: ToolCall, display_target: ?[]const u8, _: []const []const u8) ![]const u8 { return if (display_target) |target| std.fmt.allocPrint(arena, "start {s} {s}", .{ call.name, target }) else std.fmt.allocPrint(arena, "start {s}", .{call.name}); }
fn describeCompleted(_: *anyopaque, arena: Allocator, call: ToolCall, display_target: ?[]const u8, _: []const []const u8) ![]const u8 { return if (display_target) |target| std.fmt.allocPrint(arena, "done {s} {s}", .{ call.name, target }) else std.fmt.allocPrint(arena, "done {s}", .{call.name}); }
fn describeDenied(_: *anyopaque, arena: Allocator, call: ToolCall, _: ?[]const u8, label: []const u8, _: []const []const u8) ![]const u8 { return std.fmt.allocPrint(arena, "{s} {s}", .{ label, call.name }); }
fn permissionTarget(raw: *anyopaque, arena: Allocator, call: ToolCall, _: []const []const u8) ![]const u8 { const self: *FakeAgentRuntimeDeps = @ptrCast(@alignCast(raw)); if (self.resolve_permission_target) { return permissions.permissionTargetForCall( arena, self.permission_target, call, .none, ); } return arena.dupe(u8, self.permission_target); }
fn execute( raw: *anyopaque, request: ToolExecutionRequest, ) !ToolExecutionResult { const self: *FakeAgentRuntimeDeps = @ptrCast(@alignCast(raw)); if (self.tool_execution_override) |override| { return override.execute_fn(override.context, request); } const execute_delegate = self.execute_delegate; const call = request.call; var plan: FakeExecPlan = undefined; var should_cancel = false; var should_return_ordinary_cancel = false; var swap_link: ?[]const u8 = null; var swap_target: ?[]const u8 = null; { self.execute_mutex.lockUncancelable(io_mod.getIo()); defer self.execute_mutex.unlock(io_mod.getIo());
try self.executed_names.append(self.alloc, try self.alloc.dupe(u8, call.name)); try self.executed_call_ids.append(self.alloc, try self.alloc.dupe(u8, call.id)); try self.execution_classification_complete.append( self.alloc, request.classification_complete, ); try self.execution_mcp_runtime_generations.append( self.alloc, request.expected_mcp_runtime_generation, ); try self.execute_timeout_started_ms.append( self.alloc, request.command_timeout_started_ms, ); if (self.last_executed_arguments) |value| self.alloc.free(value); self.last_executed_arguments = try self.alloc.dupe(u8, call.arguments_json); if (self.last_execute_credential) |value| self.alloc.free(value); self.last_execute_credential = try self.alloc.dupe(u8, request.credential.secret() orelse ""); if (self.last_execute_root_user_intent_context) |value| self.alloc.free(value); self.last_execute_root_user_intent_context = try self.alloc.dupe( u8, request.root_user_intent_context, ); freeStringList(self.alloc, &self.last_execute_root_user_messages); self.last_execute_root_user_messages = .empty; for (request.root_user_messages) |message| { try self.last_execute_root_user_messages.append( self.alloc, try self.alloc.dupe(u8, message), ); } self.last_execute_root_user_evidence_complete = request.root_user_evidence_complete; self.last_execute_permission_mode = request.permission_mode; try self.record("execute:{s}", .{call.name}); self.last_execute_grant_count = request.session_grants.len; for (self.last_execute_grants.items) |grant| { self.alloc.free(grant.tool_name); self.alloc.free(grant.target_path); } self.last_execute_grants.clearRetainingCapacity(); for (request.session_grants) |grant| { try self.last_execute_grants.append(self.alloc, .{ .tool_name = try self.alloc.dupe(u8, grant.tool_name), .target_path = try self.alloc.dupe(u8, grant.target_path), }); } if (request.live_authority) |live| { self.last_live_authority_generation = live.generation; self.last_live_authority_tool_count = live.tools.len; self.last_live_authority_integration_count = live.integrations.len; self.last_live_authority_rule_count = live.rules.rules.len; self.last_live_authority_grant_count = live.grants.len; } else { self.last_live_authority_generation = null; self.last_live_authority_tool_count = 0; self.last_live_authority_integration_count = 0; self.last_live_authority_rule_count = 0; self.last_live_authority_grant_count = 0; } const execution_index = self.exec_index; plan = if (execution_index < self.exec_plans.len) self.exec_plans[execution_index] else .{ .result = .{ .model_output = "ok" } }; self.exec_index += 1; should_cancel = (self.cancel_on_execute_index == null or self.cancel_on_execute_index.? == execution_index) and if (self.cancel_on_execute != null) if (self.cancel_on_execute_name) |name| std.mem.eql(u8, name, call.name) else true else false; should_return_ordinary_cancel = if (self.ordinary_cancel_on_execute_name) |name| std.mem.eql(u8, name, call.name) else false; if (self.swap_link_on_execute_name) |name| { if (std.mem.eql(u8, name, call.name)) { swap_link = self.swap_link_on_execute; swap_target = self.swap_link_target_on_execute; self.swap_link_on_execute_name = null; self.swap_link_on_execute = null; self.swap_link_target_on_execute = null; } } if (self.parent_turn_context_after_execute) |text| { self.parent_turn_context_text = text; self.parent_turn_context_texts = &.{}; self.parent_turn_context_after_execute = null; } }
if (swap_link) |link| { const target = swap_target orelse return error.InvalidToolArguments; var cwd = std.Io.Dir.cwd(); cwd.deleteFile(io_mod.getIo(), link) catch {}; try cwd.symLink(io_mod.getIo(), target, link, .{ .is_directory = true }); } if (should_return_ordinary_cancel) return error.Cancelled; if (should_cancel) { if (self.cancel_on_execute_delay_ms > 0) { io_mod.sleep(self.cancel_on_execute_delay_ms * std.time.ns_per_ms); } self.cancel_on_execute.?.store(true, .seq_cst); } if (execute_delegate) |delegate| { return delegate.run(delegate.ctx, request); } var result = switch (plan) { .result => |result| result, .err => |err| return err, }; if (self.command_replay_output) |output| { const capture = try command_replay_store.Capture.create( request.result_allocator, 1, self.command_replay_capability, ); capture.setPolicyBeforeCapture(.required); capture.appendAccepted(request.result_allocator, .stdout, output); capture.seal(request.result_allocator); result.command_replay_capture = capture; } if (result.committed_file_handoff != null) { self.last_file_request_allocators_distinct = request.call_allocator.ptr != request.result_allocator.ptr or request.call_allocator.vtable != request.result_allocator.vtable; result.model_output = try request.result_allocator.dupe( u8, result.model_output, ); if (result.tool_result_memory) |*memory| { if (memory.output_handle) |handle| { memory.output_handle = try request.result_allocator.dupe( u8, handle, ); } if (memory.preview) |preview| { memory.preview = try request.result_allocator.dupe( u8, preview, ); } } } if (result.status == .success and !result.cancelled) { _ = self.successful_effect_count.fetchAdd(1, .seq_cst); } if (self.tool_display_target_after_execute) |target| { self.tool_display_target = target; } return result; }
fn publishCommittedFileHandoff( raw: *anyopaque, _: file_mutation.CommittedFileHandoff, ) SecondaryPublicationReport { const self: *FakeAgentRuntimeDeps = @ptrCast(@alignCast(raw)); self.record("publish:committed_file", .{}) catch return .{ .diff = .failed, .tracker = .failed }; return self.committed_publication_report; }
fn reportCapturedInnerToolUsage(raw: *anyopaque, tool_name: []const u8, usage: types.ToolUsage) void { const self: *FakeAgentRuntimeDeps = @ptrCast(@alignCast(raw)); self.inner_usage_names.append(self.alloc, self.alloc.dupe(u8, tool_name) catch return) catch return; self.inner_usages.append(self.alloc, usage) catch return; }
fn recordRejected(raw: *anyopaque, _: Allocator, call: ToolCall, _: []const u8, _: ?[]const u8) !void { const self: *FakeAgentRuntimeDeps = @ptrCast(@alignCast(raw)); try self.rejected_names.append(self.alloc, try self.alloc.dupe(u8, call.name)); try self.record("rejected:{s}", .{call.name}); }
fn recordFailed(raw: *anyopaque, _: Allocator, call: ToolCall, _: []const u8, _: ?[]const u8) !void { const self: *FakeAgentRuntimeDeps = @ptrCast(@alignCast(raw)); try self.failed_names.append(self.alloc, try self.alloc.dupe(u8, call.name)); try self.record("failed:{s}", .{call.name}); }
fn commitCompaction(raw: *anyopaque, summary: types.CompactedSummaryHistoryTurn, active_prefix: ?types.AssistantHistoryTurn, _: ?types.ContextHistoryCut) !void { const self: *FakeAgentRuntimeDeps = @ptrCast(@alignCast(raw)); const owned = if (active_prefix) |prefix| try types.dupeHistoryTurn(self.alloc, .{ .assistant = prefix }) else null; errdefer if (owned) |turn| types.freeHistoryTurn(self.alloc, turn); try self.compaction_prefixes.ensureUnusedCapacity(self.alloc, 1); try propagateHistory(raw, .{ .compacted_summary = summary }); self.compaction_prefixes.appendAssumeCapacity(owned); }
fn propagateHistory(raw: *anyopaque, turn: HistoryTurn) !void { const self: *FakeAgentRuntimeDeps = @ptrCast(@alignCast(raw)); self.history_propagation_count += 1; if (self.history_propagation_error) |err| return err; const copied_turn = try types.dupeHistoryTurn(self.alloc, turn); errdefer types.freeHistoryTurn(self.alloc, copied_turn); try self.history_turns.append(self.alloc, copied_turn); switch (turn) { .assistant => |entry| { if (self.history_assistant_text) |value| self.alloc.free(value); self.history_assistant_text = try self.alloc.dupe(u8, entry.assistant); try self.record("history:assistant", .{}); }, .interrupted => |entry| { self.interrupted_history_count += 1; if (entry.tool_call) |tool_call| { if (self.interrupted_tool_name) |value| self.alloc.free(value); self.interrupted_tool_name = try self.alloc.dupe(u8, tool_call.name); } try self.record("history:interrupted", .{}); }, .compacted_summary => {}, } }
fn propagateGrant(raw: *anyopaque, tool_name: []const u8, target_path: []const u8) !void { const self: *FakeAgentRuntimeDeps = @ptrCast(@alignCast(raw)); try appendGrant(self.alloc, &self.propagated_grants, .{ .tool_name = @constCast(tool_name), .target_path = @constCast(target_path), }); try self.record("propagate_grant:{s}:{s}", .{ tool_name, target_path }); }
fn pushEvent(raw: *anyopaque, event: WorkerEvent) !void { const self: *FakeAgentRuntimeDeps = @ptrCast(@alignCast(raw)); defer worker_runtime.freeWorkerEvent(std.heap.c_allocator, event); switch (event) { .full_detail_record => |notice| { const owned = try types.dupeSemanticNotice(self.alloc, notice); errdefer types.freeSemanticNotice(self.alloc, owned); try self.full_detail_records.append(self.alloc, owned); try self.record("full_detail_record:{s}:{s}", .{ notice.topic, notice.body }); }, .clear_route_recovery_status => { self.route_recovery_clear_count += 1; try self.record("event:clear_route_recovery_status", .{}); }, .finish_prompt => |finished| { self.finish_event_attempt_count += 1; if (self.finish_event_error) |err| return err; self.finish_event_count += 1; self.finish_summary = finished.summary; self.finish_projection = finished.terminal_projection; self.finish_terminal_outcome = finished.terminal_outcome; if (self.finish_presentation_text) |value| self.alloc.free(value); self.finish_presentation_text = null; if (finished.presentation_text) |value| { self.finish_presentation_text = try self.alloc.dupe(u8, value); } switch (finished.turn) { .assistant => |entry| { if (self.finish_assistant_text) |value| self.alloc.free(value); self.finish_assistant_text = try self.alloc.dupe(u8, entry.assistant); }, .interrupted => self.interrupted_event_count += 1, .compacted_summary => {}, } try self.record("event:finish_prompt", .{}); }, .session_grant => |grant| { try appendGrant(self.alloc, &self.event_grants, grant); try self.record("event:session_grant:{s}:{s}", .{ grant.tool_name, grant.target_path }); }, .turn_token_update => |update| { if (update.output_tokens > 0) { if (self.stream_output_token_error) |err| return err; } try self.token_updates.append(self.alloc, update); try self.record( "event:turn_tokens:{d}:{d}:{s}:{s}", .{ update.input_tokens, update.output_tokens, if (update.input_exact) "exact" else "approx", if (update.output_exact) "exact" else "approx", }, ); }, else => {}, } }
fn pushText(raw: *anyopaque, emission: runtime_deps.TextEmission) !void { const self: *FakeAgentRuntimeDeps = @ptrCast(@alignCast(raw)); const text = switch (emission) { .assistant_started => return, .assistant_source => |text| { try self.assistant_sources.append(self.alloc, try self.alloc.dupe(u8, text)); return; }, .assistant_rendered => |text| text, .assistant_restarted => |text| text, .operational => |text| text, }; try self.texts.append(self.alloc, try self.alloc.dupe(u8, text)); if (self.cancel_on_text) |flag| { const should_cancel = if (self.cancel_on_text_match) |expected| std.mem.eql(u8, expected, text) else true; if (should_cancel) flag.store(true, .seq_cst); } if (std.mem.eql(u8, text, "\n")) { try self.record("text:newline", .{}); } else { try self.record("text:{s}", .{text}); } }
fn pushToolLifecycle( raw: *anyopaque, event: types.ToolLifecycleEvent, ) !void { const self: *FakeAgentRuntimeDeps = @ptrCast(@alignCast(raw)); switch (event) { .provisional, .authoritative_started => try self.record("status:started", .{}), .terminal => |terminal| { try self.record("status:finished:{s}", .{terminal.outcome.summary}); if (self.fail_status_finished) return error.TestStatusPublicationFailure; }, .progress, .turn_finished => {}, } const owned = try worker_runtime.dupeToolLifecycleEvent(self.alloc, event); errdefer worker_runtime.freeToolLifecycleEvent(self.alloc, owned); try self.lifecycle_events.append(self.alloc, owned); }
fn pushDiff(raw: *anyopaque, payload: DiffEntryPayload) !void { const self: *FakeAgentRuntimeDeps = @ptrCast(@alignCast(raw)); self.diff_count += 1; if (self.diff_preview) |value| self.alloc.free(value); self.diff_preview = try self.alloc.dupe(u8, payload.preview); try self.record("diff", .{}); }
fn systemNotice(raw: *anyopaque, text: []const u8) !void { const self: *FakeAgentRuntimeDeps = @ptrCast(@alignCast(raw)); try self.system_notices.append(self.alloc, try self.alloc.dupe(u8, text)); try self.record("system_notice:{s}", .{text}); }
fn interactiveNotice(raw: *anyopaque, notice: types.SemanticNotice) !void { const self: *FakeAgentRuntimeDeps = @ptrCast(@alignCast(raw)); const owned = try types.dupeSemanticNotice(self.alloc, notice); errdefer types.freeSemanticNotice(self.alloc, owned); try self.record("interactive_notice:{s}:{s}", .{ notice.topic, notice.body }); try self.interactive_notices.append(self.alloc, owned); }
fn contextNotice(raw: *anyopaque, text: []const u8) !void { const self: *FakeAgentRuntimeDeps = @ptrCast(@alignCast(raw)); try self.context_notices.append(self.alloc, try self.alloc.dupe(u8, text)); try self.record("context_notice:{s}", .{text}); }
fn routeRecoveryStatus(raw: *anyopaque, status: types.RouteRecoveryStatus) !void { const self: *FakeAgentRuntimeDeps = @ptrCast(@alignCast(raw)); if (status.kind == .auto_retry and status.retry_deadline == null and self.route_recovery_status_error_attempt == status.failed_attempt) { return error.TestRouteRecoveryPublicationFailed; } try self.route_recovery_statuses.append(self.alloc, status); if (status.kind == .auto_retry and status.retry_deadline != null) { if (self.cancel_on_auto_retry_status) |flag| { if (self.cancel_on_auto_retry_attempt == null or self.cancel_on_auto_retry_attempt.? == status.failed_attempt) { flag.store(true, .seq_cst); } } } if (self.pause_on_auto_retry_status and status.kind == .auto_retry and status.retry_deadline != null and (self.pause_on_auto_retry_attempt == null or self.pause_on_auto_retry_attempt.? == status.failed_attempt)) { if (self.recovery_pause_flag) |flag| flag.store(true, .seq_cst); } var label_buf: [types.RouteRecoveryStatus.label_max_bytes]u8 = undefined; try self.record("route_recovery_status:{s}", .{status.label(&label_buf)}); }
fn commandOutputComplete(raw: *anyopaque, lifecycle_id: ?types.ToolLifecycleId) !void { const self: *FakeAgentRuntimeDeps = @ptrCast(@alignCast(raw)); self.command_complete_count += 1; if (lifecycle_id) |id| { try self.record("command_output_complete:{d}:{s}", .{ id.turn_id, id.call_id }); } else { try self.record("command_output_complete", .{}); } }
fn httpError(raw: *anyopaque, status: std.http.Status, detail: []const u8, credential_source: ?types.CredentialSource) !void { const self: *FakeAgentRuntimeDeps = @ptrCast(@alignCast(raw)); self.http_status = status; self.http_credential_source = credential_source; if (self.http_detail) |value| self.alloc.free(value); self.http_detail = try self.alloc.dupe(u8, detail); try self.record("http_error", .{}); }
fn formatError(_: *anyopaque, arena: Allocator, tool_name: []const u8, err: anyerror) ![]const u8 { return std.fmt.allocPrint(arena, "Tool {s} failed: {s}", .{ tool_name, @errorName(err) }); }};
pub const PromptFixture = struct { images: [0]types.ImageAttachment = .{}, history: [0]HistoryTurn = .{}, grants: [0]PermissionGrant = .{}, cancel_flag: std.atomic.Value(bool) = std.atomic.Value(bool).init(false), workspace_root: []const u8 = "/tmp/workspace",
pub fn job(self: *PromptFixture) QueuedPrompt { return .{ .prompt = @constCast("user prompt"), .images = self.images[0..], .model = @constCast("anthropic/claude-opus-4.6"), .api_key = @constCast("key"), .credential_source = .ai_gateway_api_key, .permission_mode = .ask, .history = self.history[0..], .grants = self.grants[0..], }; }
pub fn config(self: *PromptFixture) Config { return .{ .system_prompt = "system", .gateway_retry_count = 1, .max_provider_attempts = model_response_recovery.default_max_provider_attempts, .gateway_chat_url = "https://example.invalid", .agent_step_limit = 8, .cancel_flag = &self.cancel_flag, .workspace_root = self.workspace_root, }; }};
pub const PreToolUseTestHandler = struct { pub const Action = union(enum) { continue_, rewrite: []const u8, block: []const u8, fail, cancel_error, cancel_continue, };
alloc: Allocator, action: Action, cancel_flag: ?*std.atomic.Value(bool) = null, calls: usize = 0, seen_arguments: std.ArrayList([]u8) = .empty,
pub fn deinit(self: *PreToolUseTestHandler) void { freeStringList(self.alloc, &self.seen_arguments); }
fn run( raw: *anyopaque, input: lifecycle_hooks.PreToolUseInput, ) lifecycle_hooks.HandlerError!lifecycle_hooks.PreToolUseAction { const self: *PreToolUseTestHandler = @ptrCast(@alignCast(raw)); self.calls += 1; const arguments = self.alloc.dupe(u8, input.arguments_json) catch return error.Failed; self.seen_arguments.append(self.alloc, arguments) catch { self.alloc.free(arguments); return error.Failed; };
return switch (self.action) { .continue_ => .continue_, .rewrite => |arguments_json| .{ .rewrite_arguments = arguments_json }, .block => |reason| .{ .block = reason }, .fail => error.Failed, .cancel_error => blk: { if (self.cancel_flag) |flag| flag.store(true, .seq_cst); break :blk error.Cancelled; }, .cancel_continue => blk: { if (self.cancel_flag) |flag| flag.store(true, .seq_cst); break :blk .continue_; }, }; }};
pub const StopTestHandler = struct { pub const Action = union(enum) { allow, continue_once: []const u8, fail, cancel_error, cancel_allow, cancel_continue: []const u8, };
alloc: Allocator, action: Action, cancel_flag: ?*std.atomic.Value(bool) = null, calls: usize = 0, seen_text: ?[]u8 = null, seen_step_index: usize = 0, seen_can_continue: bool = false, seen_disposition: ?types.ProviderCompletionDisposition = null,
pub fn deinit(self: *StopTestHandler) void { if (self.seen_text) |text| self.alloc.free(text); }
fn run( raw: *anyopaque, input: lifecycle_hooks.StopInput, ) lifecycle_hooks.HandlerError!lifecycle_hooks.StopAction { const self: *StopTestHandler = @ptrCast(@alignCast(raw)); self.calls += 1; if (self.seen_text) |text| self.alloc.free(text); self.seen_text = self.alloc.dupe(u8, input.assistant_text) catch return error.Failed; self.seen_step_index = input.step_index; self.seen_can_continue = input.can_continue; self.seen_disposition = input.provider_disposition;
return switch (self.action) { .allow => .allow, .continue_once => |context| .{ .continue_once = context }, .fail => error.Failed, .cancel_error => error.Cancelled, .cancel_allow => blk: { if (self.cancel_flag) |flag| flag.store(true, .seq_cst); break :blk .allow; }, .cancel_continue => |context| blk: { if (self.cancel_flag) |flag| flag.store(true, .seq_cst); break :blk .{ .continue_once = context }; }, }; }};
pub fn registerPreToolUseTestHandler( runtime: *lifecycle_hooks.Runtime, handler: *PreToolUseTestHandler,) !lifecycle_hooks.RuntimeView { try runtime.registerPreToolUse(.{ .name = "test-pre-tool-use", .ctx = handler, .run = PreToolUseTestHandler.run, }); return runtime.freeze();}
pub fn registerStopTestHandler( runtime: *lifecycle_hooks.Runtime, handler: *StopTestHandler,) !lifecycle_hooks.RuntimeView { try runtime.registerStop(.{ .name = "test-stop", .ctx = handler, .run = StopTestHandler.run, }); return runtime.freeze();}
pub fn testLifecycleContext( view: lifecycle_hooks.RuntimeView, alloc: Allocator, workspace_root: []const u8,) runtime_lifecycle.LifecycleContext { return .{ .view = view, .scope = .{ .kind = .interactive, .workspace_root = workspace_root, }, .outcome_allocator = alloc, };}
pub fn runFakePrompt(gateway: *FakeGateway, hooks: *FakeAgentRuntimeDeps, config: Config, job: QueuedPrompt) !void { return runFakePromptWithLifecycle( gateway, hooks, config, job, testLifecycleContext( lifecycle_hooks.RuntimeView.empty(), hooks.alloc, config.workspace_root, ), );}
pub fn runFakePromptWithLifecycle( gateway: *FakeGateway, hooks: *FakeAgentRuntimeDeps, config: Config, job: QueuedPrompt, lifecycle: runtime_lifecycle.LifecycleContext,) !void { hooks.workspace_root = config.workspace_root; var deps = hooks.deps(); deps.agent_stream_provider = gateway.provider(); if (hooks.execute_delegate) |delegate| { if (delegate.set_agent_stream_provider) |set_provider| { set_provider(delegate.ctx, deps.agent_stream_provider); } } var agent: runtime_agent.Agent = .{}; defer agent.deinit(hooks.alloc); try agent.restoreHistory(hooks.alloc, job.history); try runtime_orchestrator.processAgentPrompt( &agent, &deps, null, lifecycle, config, job, );}
fn syntheticFileMutationTargets( arena: Allocator, target_path: []const u8,) !file_mutation_contract.PolicyEvaluatedFileTargets { const canonical_target_path = try arena.dupe(u8, target_path); const items = try arena.alloc(file_mutation_contract.EvaluatedPermissionTarget, 1); items[0] = .{ .kind = .target, .disposition = .target_entry, .path_end = canonical_target_path.len, .expected_identity = null, .rule = .ask, .session_grant_allowed = true, }; return .{ .canonical_target_path = canonical_target_path, .anchor = .{ .scope = .workspace, .path_end = canonical_target_path.len, .identity = .{ .device = 0, .inode = 0, .kind = .directory, }, .relative_components = &.{}, }, .traversal_directories = &.{}, .items = items, .prompt_required = true, };}
fn freeStringList(alloc: Allocator, list: *std.ArrayList([]u8)) void { for (list.items) |item| alloc.free(item); list.deinit(alloc);}
fn appendGrant(alloc: Allocator, list: *std.ArrayList(PermissionGrant), grant: PermissionGrant) !void { try list.append(alloc, .{ .tool_name = try alloc.dupe(u8, grant.tool_name), .target_path = try alloc.dupe(u8, grant.target_path), });}
fn freeGrantList(alloc: Allocator, list: *std.ArrayList(PermissionGrant)) void { for (list.items) |grant| { alloc.free(grant.tool_name); alloc.free(grant.target_path); } list.deinit(alloc);}
pub fn expectBodyContains(gateway: *const FakeGateway, index: usize, needle: []const u8) !void { try std.testing.expect(index < gateway.request_bodies.items.len); try std.testing.expect(std.mem.find(u8, gateway.request_bodies.items[index], needle) != null);}
pub fn expectBodyNotContains(gateway: *const FakeGateway, index: usize, needle: []const u8) !void { try std.testing.expect(index < gateway.request_bodies.items.len); try std.testing.expect(std.mem.find(u8, gateway.request_bodies.items[index], needle) == null);}pub fn expectBodyContainsInOrder(gateway: *const FakeGateway, index: usize, needles: []const []const u8) !void { try std.testing.expect(index < gateway.request_bodies.items.len); const body = gateway.request_bodies.items[index]; var cursor: usize = 0; for (needles) |needle| { const found = std.mem.indexOfPos(u8, body, cursor, needle) orelse return error.TestExpectedBodyNeedleMissing; cursor = found + needle.len; }}
fn countPromptContentText(value: std.json.Value, needle: []const u8) usize { return switch (value) { .string => |text| std.mem.count(u8, text, needle), .array => |array| count: { var total: usize = 0; for (array.items) |part| { if (part != .object) continue; if (part.object.get("text")) |text| { if (text == .string) total += std.mem.count(u8, text.string, needle); } if (part.object.get("output")) |output| { if (output == .object) { if (output.object.get("value")) |value_text| { if (value_text == .string) total += std.mem.count(u8, value_text.string, needle); } } } } break :count total; }, else => 0, };}
pub fn countPromptEntryText(entry: std.json.Value, needle: []const u8) usize { if (entry != .object) return 0; const content = entry.object.get("content") orelse return 0; return countPromptContentText(content, needle);}pub fn expectGatewayPromptFinalUserText(gateway: *const FakeGateway, index: usize, expected_text: []const u8) !void { const alloc = std.testing.allocator; try std.testing.expect(index < gateway.request_bodies.items.len);
var parsed = try std.json.parseFromSlice(std.json.Value, alloc, gateway.request_bodies.items[index], .{}); defer parsed.deinit();
const prompt = parsed.value.object.get("prompt").?.array.items; try std.testing.expect(prompt.len > 0); var i = prompt.len; while (i > 0) { i -= 1; const entry = prompt[i]; if (entry != .object) continue; const role = entry.object.get("role") orelse continue; if (role != .string or !std.mem.eql(u8, role.string, @tagName(types.ChatRole.user))) continue; try std.testing.expectEqual(@as(usize, 1), countPromptEntryText(entry, expected_text)); return; } return error.TestExpectedPromptMessageMissing;}
pub fn countText(hooks: *const FakeAgentRuntimeDeps, needle: []const u8) usize { var count: usize = 0; for (hooks.texts.items) |text| { if (std.mem.eql(u8, text, needle)) count += 1; } return count;}
pub fn countNeedle(haystack: []const u8, needle: []const u8) usize { var count: usize = 0; var pos: usize = 0; while (std.mem.indexOfPos(u8, haystack, pos, needle)) |found| { count += 1; pos = found + needle.len; } return count;}
pub fn readTraceFile(alloc: Allocator, trace_path: []const u8, max_bytes: usize) ![]u8 { var trace_file = try std.Io.Dir.openFileAbsolute(io_mod.getIo(), trace_path, .{}); defer trace_file.close(io_mod.getIo()); return io_mod.readFileToEnd(alloc, &trace_file, max_bytes);}
pub fn textContains(hooks: *const FakeAgentRuntimeDeps, needle: []const u8) bool { for (hooks.texts.items) |text| { if (std.mem.find(u8, text, needle) != null) return true; } return false;}
pub fn logIndex(hooks: *const FakeAgentRuntimeDeps, needle: []const u8) ?usize { for (hooks.log.items, 0..) |entry, i| { if (std.mem.eql(u8, entry, needle)) return i; } return null;}
pub fn toolCall(id: []const u8, name: []const u8, args: []const u8) ToolCall { return .{ .id = id, .name = name, .arguments_json = args };}