1489 lines · 57.3 KB · Zig
RawDownload
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.