const std = @import("std");const background_runtime = @import("../background/background_runtime.zig");const command_admission = @import("../permissions/command_admission.zig");const core_permissions = @import("../permissions/permissions.zig");const core_types = @import("../shared/types.zig");const debug_trace = @import("../shared/debug_trace.zig");const devbox_executor = @import("../execution/devbox_executor.zig");const command_environment = @import("../execution/command_environment.zig");const file_mutation_contract = @import("file_mutation_contract.zig");const io_mod = @import("../shared/io.zig");const message = @import("../shared/message.zig");const mod_registry = @import("../mods/registry.zig");const permission_gate = @import("../permissions/permission_gate.zig");const change_tracker = @import("../workspace/change_tracker.zig");const read_tracker_mod = @import("../workspace/read_tracker.zig");const session_child_store = @import("../session/session_child_store.zig");const sandbox = @import("../permissions/sandbox.zig");const subagent_tool_provider = @import("../subagent/tool_provider.zig");const text_utils = @import("../shared/text_utils.zig");const web_fetch_runtime = @import("web_fetch_runtime.zig");const web_fetch_artifacts = @import("../session/web_fetch_artifacts.zig");const gateway_schema = @import("gateway_schema.zig");const host = @import("../hosts/host.zig");const tool_result_errors = @import("tool_result_errors.zig");const tool_result_limits = @import("tool_result_limits.zig");const tool_mcp_runtime = @import("tool_mcp_runtime.zig");const web_search_contract = @import("web_search_contract.zig");const context_limits = @import("../config/context_limits.zig");const workspace_access = @import("../workspace/workspace_access.zig");const terminal_client_runtime = @import("../terminal/client.zig");const terminal_contracts = @import("../terminal/contracts.zig");const tool_args = @import("tool_args.zig"); const Allocator = std.mem.Allocator; pub const default_ignored_list_entries = [_][]const u8{ ".git", ".zig-cache", "zig-out", "node_modules", ".next", "dist", "build", "coverage",};pub const default_max_list_entries: usize = 100;pub const default_max_read_file_bytes: usize = 50 * 1024;pub const default_max_read_file_lines: usize = 400;pub const default_max_read_file_line_len: usize = 2000; pub const web_search_unavailable_message = "web_search is unavailable: no local runtime with a configured Gateway transport policy is installed";pub const web_fetch_unavailable_message = "web_fetch is unavailable: no local WebFetch runtime is installed";pub const terminal_unavailable_message = "{\"error\":{\"tool\":\"terminal\",\"code\":\"unsupported_host\",\"retryable\":false}}"; pub const ToolCapabilities = struct { web_search_runtime_ready: bool = false, terminal: host.TerminalSupport = .unsupported, pub fn for_host(host_capabilities: host.Capabilities) ToolCapabilities { return .{ .terminal = host_capabilities.terminal }; } pub fn terminalAvailable(self: ToolCapabilities) bool { return self.terminal.isSupported(); }}; pub const WebSearchProgressFn = *const fn (*anyopaque, []const u8, core_types.WebSearchProgress) void;pub const WebFetchProgressFn = *const fn (*anyopaque, []const u8, core_types.WebFetchProgress) void; pub const WebSearchBackendFn = *const fn ( *anyopaque, DispatchContext, web_search_contract.Request,) anyerror!web_search_contract.ExecutionOutput; pub const WebSearchBackend = struct { ctx: *anyopaque, execute_fn: WebSearchBackendFn, pub fn execute( self: WebSearchBackend, ctx: DispatchContext, request: web_search_contract.Request, ) !web_search_contract.ExecutionOutput { return self.execute_fn(self.ctx, ctx, request); }}; pub const VisionProviderFn = *const fn ( ?*anyopaque, DispatchContext, ToolInput,) DispatchError!ToolResult; pub const VisionProvider = struct { ctx: ?*anyopaque = null, execute_fn: VisionProviderFn, pub fn execute( self: VisionProvider, ctx: DispatchContext, input: ToolInput, ) DispatchError!ToolResult { return self.execute_fn(self.ctx, ctx, input); }}; pub const SelectedDynamicToolSinkFn = *const fn ( ?*anyopaque, []const u8, []const u8,) error{OutOfMemory}!void; pub const ContextNoticeSinkFn = *const fn (?*anyopaque, []const u8) error{OutOfMemory}!void; /// Erased, owned typed input decoded by a concrete tool.pub const ToolInput = struct { ptr: *anyopaque, deinit_fn: *const fn (ptr: *anyopaque, alloc: Allocator) void, /// Casts the erased input back to the tool's concrete input type. pub fn as(self: ToolInput, comptime T: type) *T { return @ptrCast(@alignCast(self.ptr)); } /// Frees the concrete input through the tool-provided destructor. pub fn deinit(self: ToolInput, alloc: Allocator) void { self.deinit_fn(self.ptr, alloc); }}; /// Owned success or failure text returned by a tool call.pub const ToolResult = union(enum) { success: []u8, failure: []u8, /// Frees the owned result text. pub fn deinit(self: ToolResult, alloc: Allocator) void { switch (self) { .success => |body| alloc.free(body), .failure => |body| alloc.free(body), } }}; /// Result of decoding a raw JSON argument buffer into a typed input.pub const DecodeResult = union(enum) { input: ToolInput, failure: []u8,}; /// Errors that stop local dispatch before a model-recoverable result is built.pub const DispatchError = std.json.ParseError(std.json.Scanner) || error{ OutOfMemory, InvalidToolArguments, InvalidPath, FileNotFound, HomeNotSet, PathOutsideWorkspace, WorkspaceUnavailable, Cancelled,}; /// Core-owned execution backend used by the registered run_command callback.pub const RunCommandRequest = struct { command: []const u8, resolved_cwd: []const u8, environment: command_environment.Environment,}; pub const RunCommandBackendFn = *const fn ( ?*anyopaque, DispatchContext, RunCommandRequest,) DispatchError!ToolResult; pub const RunCommandBackend = struct { ctx: ?*anyopaque = null, execute_fn: RunCommandBackendFn, pub fn execute( self: RunCommandBackend, ctx: DispatchContext, request: RunCommandRequest, ) DispatchError!ToolResult { return self.execute_fn(self.ctx, ctx, request); }}; /// Context shared by core tool dispatch, validation, and execution.pub const DispatchContext = struct { allocator: Allocator, permission_mode: permission_gate.PermissionMode = .ask, permission_decider: ?PermissionDecider = null, execution_authority: ?command_admission.ToolExecutionAuthority = null, workspace_root: []const u8 = "", access_scope: ?workspace_access.AccessScope = null, ignored_list_entries: []const []const u8 = &default_ignored_list_entries, max_list_entries: usize = default_max_list_entries, max_read_file_bytes: usize = default_max_read_file_bytes, max_read_file_lines: usize = default_max_read_file_lines, max_read_file_line_len: usize = default_max_read_file_line_len, max_tool_result_bytes: usize = tool_result_limits.default_max_tool_result_bytes, skills_dir: []const u8 = "", context_limits: context_limits.Values = .{}, permission_ctx: ?*const PermissionContext = null, read_tracker: ?*read_tracker_mod.ReadTracker = null, change_tracker: ?*change_tracker.ChangeTracker = null, cancel_flag: ?*std.atomic.Value(bool) = null, output_chunk_lifecycle_id: ?core_types.ToolLifecycleId = null, output_chunk_ctx: ?*anyopaque = null, on_output_chunk: ?sandbox.CommandOutputCallback = null, background_ctx: ?*background_runtime.BackgroundRuntime = null, background_url_ctx: ?*anyopaque = null, on_background_url_ready: ?*const fn (*anyopaque, []const u8, []const u8) void = null, background_log_dir: ?[]const u8 = null, command_artifact_dir: ?[]const u8 = null, tool_result_dir: ?[]const u8 = null, session_child_capability: ?*session_child_store.SessionChildCapability = null, terminal_client: ?*terminal_client_runtime.Runtime = null, terminal_owner_session_id: ?[]const u8 = null, terminal_transport_role: terminal_contracts.TransportRole = .interactive, background_lifecycle_allocator: Allocator = std.heap.c_allocator, command_timeout_ms: ?usize = null, sandbox_backend: sandbox.BackendKind = .none, devbox_provider: ?devbox_executor.Provider = null, captured_command_host: command_environment.Host = .native, run_command_backend: ?RunCommandBackend = null, subagent_provider: ?subagent_tool_provider.Provider = null, vision_provider: ?VisionProvider = null, ask_question_ctx: ?*anyopaque = null, ask_question_batch: ?AskQuestionBatchFn = null, tool_capabilities: ToolCapabilities = .{}, web_fetch_runtime: ?*web_fetch_runtime.Runtime = null, web_fetch_artifact_store: ?*web_fetch_artifacts.Store = null, web_fetch_artifact_error: ?anyerror = null, web_search_backend: ?WebSearchBackend = null, tool_call_id: []const u8 = "", tool_call_name: []const u8 = "", web_search_progress_ctx: ?*anyopaque = null, on_web_search_progress: ?WebSearchProgressFn = null, web_fetch_progress_ctx: ?*anyopaque = null, on_web_fetch_progress: ?WebFetchProgressFn = null, mcp_ctx: ?*anyopaque = null, mcp_call_tool: ?tool_mcp_runtime.CallToolFn = null, mcp_search_tools: ?tool_mcp_runtime.SearchToolsFn = null, mcp_tool_schema: ?tool_mcp_runtime.ToolSchemaFn = null, mcp_call_feature: ?tool_mcp_runtime.FeatureCallFn = null, mcp_access: tool_mcp_runtime.Access = .unrestricted, mcp_input_responder: ?tool_mcp_runtime.InputResponder = null, mcp_call_options: tool_mcp_runtime.CallOptions = .{}, mcp_call_status_sink: ?*?tool_mcp_runtime.CallStatus = null, mcp_execution_error_sink: ?*?anyerror = null, mcp_permission_rules: core_types.PermissionRuleSet = .{}, selected_dynamic_tool_ctx: ?*anyopaque = null, on_selected_dynamic_tool: ?SelectedDynamicToolSinkFn = null, context_notice_ctx: ?*anyopaque = null, on_context_notice: ?ContextNoticeSinkFn = null, inner_usage_sink: ?*?core_types.ToolUsage = null, web_search_completion_sink: ?*?core_types.WebSearchCompletion = null, web_fetch_completion_sink: ?*?core_types.WebFetchCompletion = null, tool_result_memory_sink: ?*?core_types.ToolResultMemory = null,}; /// Function pointer used by ask_user_question to request live user answers.pub const AskQuestionBatchFn = *const fn ( ?*anyopaque, Allocator, []const core_types.QuestionBatchEntry,) anyerror!?[][]u8; /// Function pointer used to override permission decisions in tests and callers.pub const PermissionDecider = *const fn (*const Tool, ToolInput, DispatchContext) permission_gate.Decision; /// Rule-engine lookup function carried through dispatch for test injection.pub const PermissionRuleLookup = *const fn ( Allocator, core_types.PermissionRuleSet, []const u8, []const u8, []const u8, PermissionTargetKind,) anyerror!core_permissions.RuleDecision; /// Permission state shared by a noninteractive turn.pub const PermissionContext = struct { rules: ?*const core_types.PermissionRuleSet = null, rule_lookup: PermissionRuleLookup = core_permissions.ruleDecisionFor,}; /// Function pointer that decodes JSON arguments into a concrete input.pub const DecodeFn = *const fn (DispatchContext, []const u8) DispatchError!DecodeResult; /// Optional pure validation step run before the permission gate.pub const ValidateFn = *const fn (DispatchContext, ToolInput) DispatchError!?[]u8; /// Function pointer that executes a validated and allowed tool input.pub const CallFn = *const fn (DispatchContext, ToolInput) DispatchError!ToolResult; /// Optional Core adapter selected by a registered tool descriptor when the/// ordinary decode/validate/call path needs a focused lifecycle wrapper.pub const AuthorizedCallAdapterFn = *const fn ( DispatchContext, Registry, message.ToolCall,) DispatchError!DispatchResult; /// Optional Core mapper selected by a registered tool descriptor after an/// authorized call has produced its structured dispatch result.pub const AuthorizedResultMapperFn = *const fn ( Allocator, DispatchResult,) Allocator.Error!DispatchResult; pub const RunCommandCompatibility = struct { matches: *const fn ([]const u8) bool, /// Returns success or failure text owned by `ctx.allocator`. execute: *const fn (DispatchContext, []const u8) DispatchError!ToolResult,}; /// Consumes a decoded tool input and transfers its owned fields into Core's/// canonical file-mutation contract. The caller owns the returned input and/// must not deinitialize the consumed ToolInput.pub const TakeFileMutationInputFn = *const fn ( ToolInput, Allocator,) file_mutation_contract.FileMutationInput; /// Function pointer classifying whether an input is read-only.pub const ReadsOnlyFn = *const fn (ToolInput) bool; /// Function pointer classifying whether an input is irreversible.pub const IrreversibleFn = *const fn (ToolInput) bool; pub const GatewayAdvertisementError = std.mem.Allocator.Error || std.Io.Writer.Error || error{ InvalidWebSearchBackend, ConflictingDomainFilters, InvalidGatewayAdvertisement,}; pub const WriteGatewayAdvertisementFn = *const fn ( std.mem.Allocator, *std.Io.Writer,) GatewayAdvertisementError!void; pub const LabelArgKind = enum { none, name, path, pattern, url, command, description, source, old_path, action, query, selector,}; pub const PermissionTargetKind = core_permissions.PermissionTargetKind; pub const ExecutorKind = enum { list_files, glob_files, grep_files, read_file, read_tool_result, write_file, edit_file, delete_file, rename_file, copy_file, create_folder, file_info, memory, semantic_search, open_file, web_fetch, web_search, run_command, terminal, skill, install_skill, subagent, mcp_search_tools, mcp_select_tool, mcp_features, ask_user_question, vision,}; pub const ApprovalPolicy = enum { standard, ask_only, auto_deny_on_ask,}; pub const RuntimeProviderKind = enum { none, run_command, subagent, vision,}; pub const CapturedCommandFn = *const fn (ToolInput) bool; pub const CallPresentation = struct { activity_kind: core_types.ToolActivityKind, action_label: []const u8, completed_action_label: []const u8, label_arg_kind: LabelArgKind, label_arg_default: []const u8,}; /// Optional call-aware presentation override. Returned strings must outlive the/// parsed arguments supplied to the callback.pub const PresentationFn = *const fn (std.json.ObjectMap) ?CallPresentation; /// Descriptor for a core tool's model-facing metadata and runtime callbacks.pub const Tool = struct { name: []const u8, description: []const u8, gateway_schema: gateway_schema.FunctionSchema, write_gateway_advertisement_fn: ?WriteGatewayAdvertisementFn = null, /// Set when the provider runs the tool instead of fx dispatch. Such a tool /// never reaches a call-time permission check, so advertisement is its only /// enforcement point and requires an already-settled allow. provider_executed: bool = false, executor_kind: ExecutorKind = .list_files, activity_kind: core_types.ToolActivityKind = .read, requires_approval: bool = false, approval_policy: ApprovalPolicy = .standard, action_label: []const u8 = "Working", completed_action_label: []const u8 = "Completed", label_arg_kind: LabelArgKind = .none, label_arg_default: []const u8 = "", presentation_fn: ?PresentationFn = null, permission_target_kind: PermissionTargetKind = .none, decode: DecodeFn, validate: ?ValidateFn = null, call: CallFn, runtime_provider: RuntimeProviderKind = .none, captured_command_host: command_environment.Host = .native, captured_command_action: ?[]const u8 = null, captured_command_fn: ?CapturedCommandFn = null, authorized_call_adapter: ?AuthorizedCallAdapterFn = null, authorized_result_mapper: ?AuthorizedResultMapperFn = null, cancel_if_requested_after_call: bool = false, run_command_compatibility: ?RunCommandCompatibility = null, take_file_mutation_input_fn: ?TakeFileMutationInputFn = null, reads_only_fn: ReadsOnlyFn, irreversible_fn: IrreversibleFn,}; pub const Registry = mod_registry.ToolRegistry(Tool); pub const ProgressLabelKind = enum { none, started, completed,}; /// Classifies rendered tool progress through the registered presentation labels.pub fn classifyProgressLabel(registry: Registry, text: []const u8) ProgressLabelKind { for (registry.tools) |tool| { if (startsWithProgressLabel(text, tool.action_label)) return .started; if (startsWithProgressLabel(text, tool.completed_action_label)) return .completed; } return .none;} fn startsWithProgressLabel(text: []const u8, label: []const u8) bool { if (!std.mem.startsWith(u8, text, label)) return false; if (text.len == label.len) return true; return text[label.len] == ' ';} pub const RunCommandCompatibilityMatch = struct { tool: *const Tool, compatibility: RunCommandCompatibility,}; pub const RunCommandCompatibilityMatchError = error{AmbiguousRunCommandCompatibility}; pub fn matchRunCommandCompatibility( registry: Registry, command: []const u8,) RunCommandCompatibilityMatchError!?RunCommandCompatibilityMatch { var matched: ?RunCommandCompatibilityMatch = null; for (registry.tools) |*tool| { const compatibility = tool.run_command_compatibility orelse continue; if (!compatibility.matches(command)) continue; if (matched != null) return error.AmbiguousRunCommandCompatibility; matched = .{ .tool = tool, .compatibility = compatibility, };Lines 1–500 of 1489. Load more
const std = @import("std"); const background_runtime = @import("../background/background_runtime.zig"); const command_admission = @import("../permissions/command_admission.zig"); const core_permissions = @import("../permissions/permissions.zig"); const core_types = @import("../shared/types.zig"); const debug_trace = @import("../shared/debug_trace.zig"); const devbox_executor = @import("../execution/devbox_executor.zig"); const command_environment = @import("../execution/command_environment.zig"); const file_mutation_contract = @import("file_mutation_contract.zig"); const io_mod = @import("../shared/io.zig"); const message = @import("../shared/message.zig"); const mod_registry = @import("../mods/registry.zig"); const permission_gate = @import("../permissions/permission_gate.zig"); const change_tracker = @import("../workspace/change_tracker.zig"); const read_tracker_mod = @import("../workspace/read_tracker.zig"); const session_child_store = @import("../session/session_child_store.zig"); const sandbox = @import("../permissions/sandbox.zig"); const subagent_tool_provider = @import("../subagent/tool_provider.zig"); const text_utils = @import("../shared/text_utils.zig"); const web_fetch_runtime = @import("web_fetch_runtime.zig"); const web_fetch_artifacts = @import("../session/web_fetch_artifacts.zig"); const gateway_schema = @import("gateway_schema.zig"); const host = @import("../hosts/host.zig"); const tool_result_errors = @import("tool_result_errors.zig"); const tool_result_limits = @import("tool_result_limits.zig"); const tool_mcp_runtime = @import("tool_mcp_runtime.zig"); const web_search_contract = @import("web_search_contract.zig"); const context_limits = @import("../config/context_limits.zig"); const workspace_access = @import("../workspace/workspace_access.zig"); const terminal_client_runtime = @import("../terminal/client.zig"); const terminal_contracts = @import("../terminal/contracts.zig"); const tool_args = @import("tool_args.zig"); const Allocator = std.mem.Allocator; pub const default_ignored_list_entries = [_][]const u8{ ".git", ".zig-cache", "zig-out", "node_modules", ".next", "dist", "build", "coverage", }; pub const default_max_list_entries: usize = 100; pub const default_max_read_file_bytes: usize = 50 * 1024; pub const default_max_read_file_lines: usize = 400; pub const default_max_read_file_line_len: usize = 2000; pub const web_search_unavailable_message = "web_search is unavailable: no local runtime with a configured Gateway transport policy is installed"; pub const web_fetch_unavailable_message = "web_fetch is unavailable: no local WebFetch runtime is installed"; pub const terminal_unavailable_message = "{\"error\":{\"tool\":\"terminal\",\"code\":\"unsupported_host\",\"retryable\":false}}"; pub const ToolCapabilities = struct { web_search_runtime_ready: bool = false, terminal: host.TerminalSupport = .unsupported, pub fn for_host(host_capabilities: host.Capabilities) ToolCapabilities { return .{ .terminal = host_capabilities.terminal }; } pub fn terminalAvailable(self: ToolCapabilities) bool { return self.terminal.isSupported(); } }; pub const WebSearchProgressFn = *const fn (*anyopaque, []const u8, core_types.WebSearchProgress) void; pub const WebFetchProgressFn = *const fn (*anyopaque, []const u8, core_types.WebFetchProgress) void; pub const WebSearchBackendFn = *const fn ( *anyopaque, DispatchContext, web_search_contract.Request, ) anyerror!web_search_contract.ExecutionOutput; pub const WebSearchBackend = struct { ctx: *anyopaque, execute_fn: WebSearchBackendFn, pub fn execute( self: WebSearchBackend, ctx: DispatchContext, request: web_search_contract.Request, ) !web_search_contract.ExecutionOutput { return self.execute_fn(self.ctx, ctx, request); } }; pub const VisionProviderFn = *const fn ( ?*anyopaque, DispatchContext, ToolInput, ) DispatchError!ToolResult; pub const VisionProvider = struct { ctx: ?*anyopaque = null, execute_fn: VisionProviderFn, pub fn execute( self: VisionProvider, ctx: DispatchContext, input: ToolInput, ) DispatchError!ToolResult { return self.execute_fn(self.ctx, ctx, input); } }; pub const SelectedDynamicToolSinkFn = *const fn ( ?*anyopaque, []const u8, []const u8, ) error{OutOfMemory}!void; pub const ContextNoticeSinkFn = *const fn (?*anyopaque, []const u8) error{OutOfMemory}!void; /// Erased, owned typed input decoded by a concrete tool. pub const ToolInput = struct { ptr: *anyopaque, deinit_fn: *const fn (ptr: *anyopaque, alloc: Allocator) void, /// Casts the erased input back to the tool's concrete input type. pub fn as(self: ToolInput, comptime T: type) *T { return @ptrCast(@alignCast(self.ptr)); } /// Frees the concrete input through the tool-provided destructor. pub fn deinit(self: ToolInput, alloc: Allocator) void { self.deinit_fn(self.ptr, alloc); } }; /// Owned success or failure text returned by a tool call. pub const ToolResult = union(enum) { success: []u8, failure: []u8, /// Frees the owned result text. pub fn deinit(self: ToolResult, alloc: Allocator) void { switch (self) { .success => |body| alloc.free(body), .failure => |body| alloc.free(body), } } }; /// Result of decoding a raw JSON argument buffer into a typed input. pub const DecodeResult = union(enum) { input: ToolInput, failure: []u8, }; /// Errors that stop local dispatch before a model-recoverable result is built. pub const DispatchError = std.json.ParseError(std.json.Scanner) || error{ OutOfMemory, InvalidToolArguments, InvalidPath, FileNotFound, HomeNotSet, PathOutsideWorkspace, WorkspaceUnavailable, Cancelled, }; /// Core-owned execution backend used by the registered run_command callback. pub const RunCommandRequest = struct { command: []const u8, resolved_cwd: []const u8, environment: command_environment.Environment, }; pub const RunCommandBackendFn = *const fn ( ?*anyopaque, DispatchContext, RunCommandRequest, ) DispatchError!ToolResult; pub const RunCommandBackend = struct { ctx: ?*anyopaque = null, execute_fn: RunCommandBackendFn, pub fn execute( self: RunCommandBackend, ctx: DispatchContext, request: RunCommandRequest, ) DispatchError!ToolResult { return self.execute_fn(self.ctx, ctx, request); } }; /// Context shared by core tool dispatch, validation, and execution. pub const DispatchContext = struct { allocator: Allocator, permission_mode: permission_gate.PermissionMode = .ask, permission_decider: ?PermissionDecider = null, execution_authority: ?command_admission.ToolExecutionAuthority = null, workspace_root: []const u8 = "", access_scope: ?workspace_access.AccessScope = null, ignored_list_entries: []const []const u8 = &default_ignored_list_entries, max_list_entries: usize = default_max_list_entries, max_read_file_bytes: usize = default_max_read_file_bytes, max_read_file_lines: usize = default_max_read_file_lines, max_read_file_line_len: usize = default_max_read_file_line_len, max_tool_result_bytes: usize = tool_result_limits.default_max_tool_result_bytes, skills_dir: []const u8 = "", context_limits: context_limits.Values = .{}, permission_ctx: ?*const PermissionContext = null, read_tracker: ?*read_tracker_mod.ReadTracker = null, change_tracker: ?*change_tracker.ChangeTracker = null, cancel_flag: ?*std.atomic.Value(bool) = null, output_chunk_lifecycle_id: ?core_types.ToolLifecycleId = null, output_chunk_ctx: ?*anyopaque = null, on_output_chunk: ?sandbox.CommandOutputCallback = null, background_ctx: ?*background_runtime.BackgroundRuntime = null, background_url_ctx: ?*anyopaque = null, on_background_url_ready: ?*const fn (*anyopaque, []const u8, []const u8) void = null, background_log_dir: ?[]const u8 = null, command_artifact_dir: ?[]const u8 = null, tool_result_dir: ?[]const u8 = null, session_child_capability: ?*session_child_store.SessionChildCapability = null, terminal_client: ?*terminal_client_runtime.Runtime = null, terminal_owner_session_id: ?[]const u8 = null, terminal_transport_role: terminal_contracts.TransportRole = .interactive, background_lifecycle_allocator: Allocator = std.heap.c_allocator, command_timeout_ms: ?usize = null, sandbox_backend: sandbox.BackendKind = .none, devbox_provider: ?devbox_executor.Provider = null, captured_command_host: command_environment.Host = .native, run_command_backend: ?RunCommandBackend = null, subagent_provider: ?subagent_tool_provider.Provider = null, vision_provider: ?VisionProvider = null, ask_question_ctx: ?*anyopaque = null, ask_question_batch: ?AskQuestionBatchFn = null, tool_capabilities: ToolCapabilities = .{}, web_fetch_runtime: ?*web_fetch_runtime.Runtime = null, web_fetch_artifact_store: ?*web_fetch_artifacts.Store = null, web_fetch_artifact_error: ?anyerror = null, web_search_backend: ?WebSearchBackend = null, tool_call_id: []const u8 = "", tool_call_name: []const u8 = "", web_search_progress_ctx: ?*anyopaque = null, on_web_search_progress: ?WebSearchProgressFn = null, web_fetch_progress_ctx: ?*anyopaque = null, on_web_fetch_progress: ?WebFetchProgressFn = null, mcp_ctx: ?*anyopaque = null, mcp_call_tool: ?tool_mcp_runtime.CallToolFn = null, mcp_search_tools: ?tool_mcp_runtime.SearchToolsFn = null, mcp_tool_schema: ?tool_mcp_runtime.ToolSchemaFn = null, mcp_call_feature: ?tool_mcp_runtime.FeatureCallFn = null, mcp_access: tool_mcp_runtime.Access = .unrestricted, mcp_input_responder: ?tool_mcp_runtime.InputResponder = null, mcp_call_options: tool_mcp_runtime.CallOptions = .{}, mcp_call_status_sink: ?*?tool_mcp_runtime.CallStatus = null, mcp_execution_error_sink: ?*?anyerror = null, mcp_permission_rules: core_types.PermissionRuleSet = .{}, selected_dynamic_tool_ctx: ?*anyopaque = null, on_selected_dynamic_tool: ?SelectedDynamicToolSinkFn = null, context_notice_ctx: ?*anyopaque = null, on_context_notice: ?ContextNoticeSinkFn = null, inner_usage_sink: ?*?core_types.ToolUsage = null, web_search_completion_sink: ?*?core_types.WebSearchCompletion = null, web_fetch_completion_sink: ?*?core_types.WebFetchCompletion = null, tool_result_memory_sink: ?*?core_types.ToolResultMemory = null, }; /// Function pointer used by ask_user_question to request live user answers. pub const AskQuestionBatchFn = *const fn ( ?*anyopaque, Allocator, []const core_types.QuestionBatchEntry, ) anyerror!?[][]u8; /// Function pointer used to override permission decisions in tests and callers. pub const PermissionDecider = *const fn (*const Tool, ToolInput, DispatchContext) permission_gate.Decision; /// Rule-engine lookup function carried through dispatch for test injection. pub const PermissionRuleLookup = *const fn ( Allocator, core_types.PermissionRuleSet, []const u8, []const u8, []const u8, PermissionTargetKind, ) anyerror!core_permissions.RuleDecision; /// Permission state shared by a noninteractive turn. pub const PermissionContext = struct { rules: ?*const core_types.PermissionRuleSet = null, rule_lookup: PermissionRuleLookup = core_permissions.ruleDecisionFor, }; /// Function pointer that decodes JSON arguments into a concrete input. pub const DecodeFn = *const fn (DispatchContext, []const u8) DispatchError!DecodeResult; /// Optional pure validation step run before the permission gate. pub const ValidateFn = *const fn (DispatchContext, ToolInput) DispatchError!?[]u8; /// Function pointer that executes a validated and allowed tool input. pub const CallFn = *const fn (DispatchContext, ToolInput) DispatchError!ToolResult; /// Optional Core adapter selected by a registered tool descriptor when the /// ordinary decode/validate/call path needs a focused lifecycle wrapper. pub const AuthorizedCallAdapterFn = *const fn ( DispatchContext, Registry, message.ToolCall, ) DispatchError!DispatchResult; /// Optional Core mapper selected by a registered tool descriptor after an /// authorized call has produced its structured dispatch result. pub const AuthorizedResultMapperFn = *const fn ( Allocator, DispatchResult, ) Allocator.Error!DispatchResult; pub const RunCommandCompatibility = struct { matches: *const fn ([]const u8) bool, /// Returns success or failure text owned by `ctx.allocator`. execute: *const fn (DispatchContext, []const u8) DispatchError!ToolResult, }; /// Consumes a decoded tool input and transfers its owned fields into Core's /// canonical file-mutation contract. The caller owns the returned input and /// must not deinitialize the consumed ToolInput. pub const TakeFileMutationInputFn = *const fn ( ToolInput, Allocator, ) file_mutation_contract.FileMutationInput; /// Function pointer classifying whether an input is read-only. pub const ReadsOnlyFn = *const fn (ToolInput) bool; /// Function pointer classifying whether an input is irreversible. pub const IrreversibleFn = *const fn (ToolInput) bool; pub const GatewayAdvertisementError = std.mem.Allocator.Error || std.Io.Writer.Error || error{ InvalidWebSearchBackend, ConflictingDomainFilters, InvalidGatewayAdvertisement, }; pub const WriteGatewayAdvertisementFn = *const fn ( std.mem.Allocator, *std.Io.Writer, ) GatewayAdvertisementError!void; pub const LabelArgKind = enum { none, name, path, pattern, url, command, description, source, old_path, action, query, selector, }; pub const PermissionTargetKind = core_permissions.PermissionTargetKind; pub const ExecutorKind = enum { list_files, glob_files, grep_files, read_file, read_tool_result, write_file, edit_file, delete_file, rename_file, copy_file, create_folder, file_info, memory, semantic_search, open_file, web_fetch, web_search, run_command, terminal, skill, install_skill, subagent, mcp_search_tools, mcp_select_tool, mcp_features, ask_user_question, vision, }; pub const ApprovalPolicy = enum { standard, ask_only, auto_deny_on_ask, }; pub const RuntimeProviderKind = enum { none, run_command, subagent, vision, }; pub const CapturedCommandFn = *const fn (ToolInput) bool; pub const CallPresentation = struct { activity_kind: core_types.ToolActivityKind, action_label: []const u8, completed_action_label: []const u8, label_arg_kind: LabelArgKind, label_arg_default: []const u8, }; /// Optional call-aware presentation override. Returned strings must outlive the /// parsed arguments supplied to the callback. pub const PresentationFn = *const fn (std.json.ObjectMap) ?CallPresentation; /// Descriptor for a core tool's model-facing metadata and runtime callbacks. pub const Tool = struct { name: []const u8, description: []const u8, gateway_schema: gateway_schema.FunctionSchema, write_gateway_advertisement_fn: ?WriteGatewayAdvertisementFn = null, /// Set when the provider runs the tool instead of fx dispatch. Such a tool /// never reaches a call-time permission check, so advertisement is its only /// enforcement point and requires an already-settled allow. provider_executed: bool = false, executor_kind: ExecutorKind = .list_files, activity_kind: core_types.ToolActivityKind = .read, requires_approval: bool = false, approval_policy: ApprovalPolicy = .standard, action_label: []const u8 = "Working", completed_action_label: []const u8 = "Completed", label_arg_kind: LabelArgKind = .none, label_arg_default: []const u8 = "", presentation_fn: ?PresentationFn = null, permission_target_kind: PermissionTargetKind = .none, decode: DecodeFn, validate: ?ValidateFn = null, call: CallFn, runtime_provider: RuntimeProviderKind = .none, captured_command_host: command_environment.Host = .native, captured_command_action: ?[]const u8 = null, captured_command_fn: ?CapturedCommandFn = null, authorized_call_adapter: ?AuthorizedCallAdapterFn = null, authorized_result_mapper: ?AuthorizedResultMapperFn = null, cancel_if_requested_after_call: bool = false, run_command_compatibility: ?RunCommandCompatibility = null, take_file_mutation_input_fn: ?TakeFileMutationInputFn = null, reads_only_fn: ReadsOnlyFn, irreversible_fn: IrreversibleFn, }; pub const Registry = mod_registry.ToolRegistry(Tool); pub const ProgressLabelKind = enum { none, started, completed, }; /// Classifies rendered tool progress through the registered presentation labels. pub fn classifyProgressLabel(registry: Registry, text: []const u8) ProgressLabelKind { for (registry.tools) |tool| { if (startsWithProgressLabel(text, tool.action_label)) return .started; if (startsWithProgressLabel(text, tool.completed_action_label)) return .completed; } return .none; } fn startsWithProgressLabel(text: []const u8, label: []const u8) bool { if (!std.mem.startsWith(u8, text, label)) return false; if (text.len == label.len) return true; return text[label.len] == ' '; } pub const RunCommandCompatibilityMatch = struct { tool: *const Tool, compatibility: RunCommandCompatibility, }; pub const RunCommandCompatibilityMatchError = error{AmbiguousRunCommandCompatibility}; pub fn matchRunCommandCompatibility( registry: Registry, command: []const u8, ) RunCommandCompatibilityMatchError!?RunCommandCompatibilityMatch { var matched: ?RunCommandCompatibilityMatch = null; for (registry.tools) |*tool| { const compatibility = tool.run_command_compatibility orelse continue; if (!compatibility.matches(command)) continue; if (matched != null) return error.AmbiguousRunCommandCompatibility; matched = .{ .tool = tool, .compatibility = compatibility, };