Something went wrong. Try again.
My version of https://github.com/vercel-labs/fx
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787const std = @import("std");const model_tool_schema = @import("model_tool_schema.zig");const permissions = @import("../permissions/permissions.zig");const tool_dispatch = @import("tool_dispatch.zig");const tool_set_contract = @import("tool_set.zig");const types = @import("../shared/types.zig");
const Allocator = std.mem.Allocator;
pub const Options = struct { permission_mode: types.PermissionMode = .auto, permission_rules: types.PermissionRuleSet = .{}, subagent_available: bool = false,};
const BuildKind = enum { full, read_only };
const TestInput = struct {};
fn testInputDeinit(ptr: *anyopaque, alloc: Allocator) void { alloc.destroy(@as(*TestInput, @ptrCast(@alignCast(ptr))));}
fn decodeTestInput(ctx: tool_dispatch.DispatchContext, _: []const u8) tool_dispatch.DispatchError!tool_dispatch.DecodeResult { const input = try ctx.allocator.create(TestInput); input.* = .{}; return .{ .input = .{ .ptr = input, .deinit_fn = testInputDeinit } };}
fn callTestTool(ctx: tool_dispatch.DispatchContext, _: tool_dispatch.ToolInput) tool_dispatch.DispatchError!tool_dispatch.ToolResult { return .{ .success = try ctx.allocator.dupe(u8, "test tool result") };}
fn testToolReadsOnly(_: tool_dispatch.ToolInput) bool { return true;}
fn testToolIsIrreversible(_: tool_dispatch.ToolInput) bool { return false;}
const test_tool_seed = tool_dispatch.Tool{ .name = "test_tool", .description = "Test registered tool.", .model_schema = .{ .name = "test_tool", .description = "Test registered tool.", }, .decode = decodeTestInput, .call = callTestTool, .reads_only_fn = testToolReadsOnly, .irreversible_fn = testToolIsIrreversible,};
const test_read_file = blk: { var spec = test_tool_seed; spec.name = "read_file"; spec.description = "Test file read. When to use: exercise registered read projection. When NOT to use: assert product-specific filesystem behavior."; spec.model_schema = .{ .name = "read_file", .description = spec.description, .input_schema = .{ .properties = &.{ .{ .name = "path", .json_type = .string }, }, .required = &.{"path"}, }, }; spec.executor_kind = .read_file; spec.activity_kind = .read; spec.requires_approval = false; spec.action_label = "Reading"; spec.completed_action_label = "Read"; spec.label_arg_kind = .path; spec.label_arg_default = "file"; spec.permission_target_kind = .path_existing; break :blk spec;};
const test_write_file = blk: { var spec = test_read_file; spec.name = "write_file"; spec.description = "Test file write. When to use: exercise registered mutation projection. When NOT to use: assert product-specific filesystem behavior."; spec.model_schema = .{ .name = "write_file", .description = spec.description, .input_schema = .{ .properties = &.{ .{ .name = "path", .json_type = .string }, .{ .name = "content", .json_type = .string }, }, .required = &.{ "path", "content" }, }, }; spec.executor_kind = .write_file; spec.activity_kind = .write; spec.requires_approval = true; spec.action_label = "Writing"; spec.completed_action_label = "Wrote"; spec.label_arg_kind = .path; spec.label_arg_default = "file"; spec.permission_target_kind = .path_create_parent; break :blk spec;};
const test_edit_file = blk: { var spec = test_read_file; spec.name = "edit_file"; spec.description = "Test file editing. When to use: exercise registered edit projection. When NOT to use: assert product-specific filesystem behavior."; spec.model_schema = .{ .name = "edit_file", .description = spec.description, .input_schema = .{ .properties = &.{ .{ .name = "path", .json_type = .string }, .{ .name = "old_string", .json_type = .string }, .{ .name = "new_string", .json_type = .string }, }, .required = &.{ "path", "old_string", "new_string" }, }, }; spec.executor_kind = .edit_file; spec.activity_kind = .edit; spec.requires_approval = true; spec.action_label = "Editing"; spec.completed_action_label = "Edited"; spec.label_arg_kind = .path; spec.label_arg_default = "file"; spec.permission_target_kind = .path_existing_parent; break :blk spec;};
const test_glob_files = blk: { var spec = test_read_file; spec.name = "glob_files"; spec.description = "Test filename matching. When to use: exercise registered search projection. When NOT to use: assert product-specific filesystem behavior."; spec.model_schema = .{ .name = "glob_files", .description = spec.description, .input_schema = .{ .properties = &.{ .{ .name = "pattern", .json_type = .string }, .{ .name = "path", .json_type = .string }, }, .required = &.{"pattern"}, }, }; spec.executor_kind = .glob_files; spec.activity_kind = .list; spec.action_label = "Matching"; spec.completed_action_label = "Matched"; spec.label_arg_kind = .pattern; spec.label_arg_default = "pattern"; break :blk spec;};
const test_grep_files = blk: { var spec = test_read_file; spec.name = "grep_files"; spec.description = "Test text search. When to use: exercise registered search projection. When NOT to use: assert product-specific filesystem behavior."; spec.model_schema = .{ .name = "grep_files", .description = spec.description, .input_schema = .{ .properties = &.{ .{ .name = "pattern", .json_type = .string }, }, .required = &.{"pattern"}, }, }; spec.executor_kind = .grep_files; spec.activity_kind = .read; spec.requires_approval = false; spec.action_label = "Searching"; spec.completed_action_label = "Searched"; spec.label_arg_kind = .pattern; spec.label_arg_default = "pattern"; spec.permission_target_kind = .path_optional_existing; break :blk spec;};
fn writeTestWebSearchProviderAdvertisement( _: Allocator, writer: *std.Io.Writer,) tool_dispatch.ProviderAdvertisementError!void { try writer.writeAll("{\"type\":\"provider\",\"id\":\"gateway.perplexity_search\",\"name\":\"perplexity_search\",\"args\":{}}");}
const test_web_fetch = blk: { var spec = test_read_file; spec.name = "web_fetch"; spec.model_schema = .{ .name = "web_fetch", .description = spec.description, }; spec.executor_kind = .web_fetch; spec.label_arg_kind = .url; spec.label_arg_default = "url"; spec.permission_target_kind = .none; break :blk spec;};
const test_web_search_base = blk: { var spec = test_web_fetch; spec.name = "web_search"; spec.description = "Test web search guidance."; spec.model_schema = .{ .name = "web_search", .description = spec.description, }; spec.executor_kind = .web_search; spec.label_arg_kind = .query; spec.label_arg_default = "web"; break :blk spec;};
const test_web_search = blk: { var spec = test_web_search_base; spec.write_provider_advertisement_fn = writeTestWebSearchProviderAdvertisement; spec.provider_executed = true; break :blk spec;};
const test_shell = blk: { var spec = test_read_file; spec.name = "shell"; spec.description = "Test shell. When to use: exercise registered shell projection. When NOT to use: assert product-specific shell behavior."; spec.model_schema = .{ .name = "shell", .description = spec.description, .input_schema = .{ .properties = &.{ .{ .name = "action", .json_type = .string, .shape = &.{ .enum_values = &.{"run"} } }, .{ .name = "command", .json_type = .string }, }, .required = &.{ "action", "command" }, .additional_properties = false, }, }; spec.executor_kind = .terminal; spec.activity_kind = .command; spec.requires_approval = true; spec.action_label = "Running shell"; spec.completed_action_label = "Ran shell"; spec.label_arg_kind = .action; spec.label_arg_default = "session"; spec.permission_target_kind = .none; break :blk spec;};
const test_skill = blk: { var spec = test_read_file; spec.name = "skill"; spec.description = "Test skill. When to use: exercise registered skill projection. When NOT to use: assert product-specific skill loading."; spec.model_schema = .{ .name = "skill", .description = spec.description, }; spec.executor_kind = .skill; spec.activity_kind = .read; spec.requires_approval = false; spec.action_label = "Loading skill"; spec.completed_action_label = "Loaded skill"; spec.label_arg_kind = .name; spec.label_arg_default = "skill"; spec.permission_target_kind = .none; break :blk spec;};
const test_capability_search = blk: { var spec = test_skill; spec.name = "capability_search"; spec.description = "Test capability search. When to use: discover skill and MCP metadata together. When NOT to use: load or execute a match."; spec.model_schema = .{ .name = "capability_search", .description = spec.description, }; spec.model_visible = true; spec.action_label = "Searching capabilities"; spec.completed_action_label = "Searched capabilities"; spec.label_arg_kind = .query; spec.label_arg_default = "capabilities"; break :blk spec;};
const test_install_skill = blk: { var spec = test_skill; spec.name = "install_skill"; spec.description = "Test install skill. When to use: exercise registered write-tool projection. When NOT to use: assert product-specific installation behavior."; spec.model_schema = .{ .name = "install_skill", .description = spec.description, }; spec.executor_kind = .install_skill; spec.activity_kind = .write; spec.requires_approval = true; spec.action_label = "Installing skill"; spec.completed_action_label = "Installed skill"; spec.label_arg_kind = .source; break :blk spec;};
const test_subagent = blk: { var spec = test_skill; spec.name = "subagent"; spec.description = "Test subagent. When to use: exercise registered subagent projection. When NOT to use: assert product-specific child management."; spec.model_schema = .{ .name = "subagent", .description = spec.description, }; spec.executor_kind = .subagent; spec.activity_kind = .subagent; spec.action_label = "Managing"; spec.completed_action_label = "Managed"; spec.label_arg_kind = .none; spec.label_arg_default = "subagent"; break :blk spec;};
const test_mcp_select_tool = blk: { var spec = test_skill; spec.name = "mcp_select_tool"; spec.description = "Test MCP selection. When to use: exercise deferred MCP projection. When NOT to use: assert product-specific MCP guidance."; spec.model_schema = .{ .name = "mcp_select_tool", .description = spec.description, .input_schema = .{ .properties = &.{ .{ .name = "name", .json_type = .string }, }, .required = &.{"name"}, }, }; spec.executor_kind = .mcp_select_tool; spec.activity_kind = .read; spec.requires_approval = false; spec.action_label = "Selecting MCP tool"; spec.completed_action_label = "Selected MCP tool"; spec.label_arg_kind = .name; spec.label_arg_default = "dynamic tool"; spec.permission_target_kind = .none; break :blk spec;};
const test_ask_user_question = blk: { var spec = test_subagent; spec.name = "ask_user_question"; spec.description = "Test user question. When to use: exercise registered interactive projection. When NOT to use: assert product-specific question behavior."; spec.model_schema = .{ .name = "ask_user_question", .description = spec.description, }; spec.executor_kind = .ask_user_question; spec.activity_kind = .ask; spec.requires_approval = false; spec.action_label = "Asking"; spec.completed_action_label = "Asked"; spec.label_arg_kind = .none; spec.label_arg_default = ""; spec.permission_target_kind = .none; break :blk spec;};
const test_vision = blk: { var spec = test_read_file; spec.name = "vision"; spec.description = "Test route-filtered vision capability."; spec.model_schema = .{ .name = "vision", .description = spec.description, }; spec.executor_kind = .vision; spec.activity_kind = .read; spec.requires_approval = true; spec.approval_policy = .ask_only; spec.action_label = "Inspecting"; spec.completed_action_label = "Inspected"; spec.label_arg_kind = .none; spec.label_arg_default = "images"; spec.permission_target_kind = .none; break :blk spec;};
const test_read_tool_result = blk: { var spec = test_read_file; spec.name = "read_tool_result"; spec.description = "Test tool result lookup. When to use: exercise registry projection. When NOT to use: assert product-specific session behavior."; spec.model_schema = .{ .name = "read_tool_result", .description = spec.description, }; spec.executor_kind = .read_tool_result; spec.activity_kind = .read; spec.requires_approval = false; spec.action_label = "Reading"; spec.completed_action_label = "Read"; spec.label_arg_kind = .path; spec.label_arg_default = "tool result"; spec.permission_target_kind = .none; break :blk spec;};
fn writeTestMirrorProviderAdvertisement( _: Allocator, writer: *std.Io.Writer,) tool_dispatch.ProviderAdvertisementError!void { try writer.writeAll("{\"type\":\"provider\",\"id\":\"gateway.mirror_search\",\"name\":\"mirror_search\",\"args\":{}}");}
const test_mirror_provider_tool = blk: { var spec = test_web_search_base; spec.name = "mirror_search"; spec.write_provider_advertisement_fn = writeTestMirrorProviderAdvertisement; spec.provider_executed = true; break :blk spec;};
/// Owns the selected registry names and any separate guidance required by/// included provider-executed tools. The caller must deinitialize the result/// with the allocator passed to the builder.pub const EffectiveToolProjection = struct { /// Borrowed registry names selected for model advertisement. The slice /// storage is owned by this projection. advertised_names: []const []const u8, /// Exact borrowed built-in schemas selected for model advertisement. The /// slice storage is owned by this projection. advertised_functions: []const model_tool_schema.FunctionSchema, custom_guidance: []u8,
pub fn deinit(self: *EffectiveToolProjection, alloc: Allocator) void { alloc.free(self.advertised_names); alloc.free(self.advertised_functions); alloc.free(self.custom_guidance); self.* = undefined; }};
pub fn containsName(names: []const []const u8, expected: []const u8) bool { for (names) |name| if (std.mem.eql(u8, name, expected)) return true; return false;}
const test_all_tools = [_]tool_dispatch.Tool{ test_glob_files, test_grep_files, test_read_file, test_write_file, test_edit_file, test_web_fetch, test_web_search, test_shell, test_capability_search, test_skill, test_install_skill, test_subagent, test_mcp_select_tool, test_ask_user_question, test_vision, test_read_tool_result,};
const test_order = [_][]const u8{ "read_file", "glob_files", "grep_files", "edit_file", "write_file", "shell", "subagent", "capability_search", "skill", "install_skill", "mcp_select_tool", "ask_user_question", "web_fetch", "web_search",};
const test_read_only_names = [_][]const u8{ "read_file", "glob_files", "grep_files",};
const test_tool_set = tool_set_contract.ToolSet{ .registry = .{ .tools = test_all_tools[0..] }, .order = test_order[0..], .read_only_tool_names = test_read_only_names[0..],};
fn testToolSetForRegistry(tools: []const tool_dispatch.Tool) tool_set_contract.ToolSet { return .{ .registry = .{ .tools = tools }, .order = test_order[0..], .read_only_tool_names = test_read_only_names[0..], };}
fn buildTestModelToolProjection(alloc: Allocator, options: Options) !EffectiveToolProjection { return buildModelToolProjectionForSet(alloc, test_tool_set, options);}
fn buildTestModelToolProjectionForRegistry(alloc: Allocator, tools: []const tool_dispatch.Tool, options: Options) !EffectiveToolProjection { return buildModelToolProjectionForSet(alloc, testToolSetForRegistry(tools), options);}
pub fn buildModelToolProjectionForSet(alloc: Allocator, tool_set: tool_set_contract.ToolSet, options: Options) !EffectiveToolProjection { return buildToolProjection(alloc, tool_set, .full, options);}
pub fn buildReadOnlyModelToolProjectionForSet(alloc: Allocator, tool_set: tool_set_contract.ToolSet, options: Options) !EffectiveToolProjection { return buildToolProjection(alloc, tool_set, .read_only, options);}
fn buildToolProjection(alloc: Allocator, tool_set: tool_set_contract.ToolSet, kind: BuildKind, options: Options) !EffectiveToolProjection { var advertised_names: std.ArrayList([]const u8) = .empty; errdefer advertised_names.deinit(alloc); var advertised_functions: std.ArrayList(model_tool_schema.FunctionSchema) = .empty; errdefer advertised_functions.deinit(alloc); var guidance_out: std.Io.Writer.Allocating = .init(alloc); errdefer guidance_out.deinit();
var first_custom_guidance = true;
for (tool_set.order) |tool_name| { const tool = tool_set.registry.lookup(tool_name) orelse continue; try appendBuiltinTool(alloc, &advertised_names, &advertised_functions, &guidance_out.writer, &first_custom_guidance, tool.*, kind, tool_set, options); }
if (kind == .full) { for (tool_set.registry.tools) |tool| { if (isCanonicalToolName(tool_set, tool.name)) continue; try appendBuiltinTool(alloc, &advertised_names, &advertised_functions, &guidance_out.writer, &first_custom_guidance, tool, kind, tool_set, options); } }
const custom_guidance = try guidance_out.toOwnedSlice(); errdefer alloc.free(custom_guidance); const names = try advertised_names.toOwnedSlice(alloc); errdefer alloc.free(names); const functions = try advertised_functions.toOwnedSlice(alloc); return .{ .advertised_names = names, .advertised_functions = functions, .custom_guidance = custom_guidance, };}fn appendBuiltinTool( alloc: Allocator, advertised_names: *std.ArrayList([]const u8), advertised_functions: *std.ArrayList(model_tool_schema.FunctionSchema), guidance_writer: *std.Io.Writer, first_custom_guidance: *bool, tool: tool_dispatch.Tool, kind: BuildKind, tool_set: tool_set_contract.ToolSet, options: Options,) !void { if (!tool.model_visible) return; if (!includeBuiltinForKind(tool.name, kind, tool_set)) return; if (std.mem.eql(u8, tool.name, "subagent") and !options.subagent_available) return; if (std.mem.eql(u8, tool.name, "vision")) return; if (options.permission_mode != .yolo) { if (tool.provider_executed and !providerExecutionIsAllowed(tool.name, options.permission_rules)) return; if (permissions.rulesDenyAllTargetsForTool(options.permission_rules, tool.name)) return; } try advertised_names.append(alloc, tool.name); if (!tool.provider_executed and tool.write_provider_advertisement_fn == null) { try advertised_functions.append(alloc, tool.model_schema); } if (tool.write_provider_advertisement_fn != null) { if (first_custom_guidance.*) { first_custom_guidance.* = false; } else { try guidance_writer.writeAll("\n\n"); } try guidance_writer.writeAll(tool.description); }}
/// A provider-executed tool is never dispatched locally, so an unsettled `ask`/// hides it exactly like a `deny`. The tool name doubles as the target pattern/// because the provider owns the call and fx never sees its arguments.fn providerExecutionIsAllowed(tool_name: []const u8, rules: types.PermissionRuleSet) bool { const permission = permissions.permissionNameForTool(tool_name); return switch (permissions.ruleDecisionForPermissionPattern(rules, permission, tool_name, .none)) { .none, .allow => true, .ask, .deny => false, };}
fn includeBuiltinForKind(tool_name: []const u8, kind: BuildKind, tool_set: tool_set_contract.ToolSet) bool { const names = builtinNamesForKind(kind, tool_set) orelse return true; return toolNameInSet(names, tool_name);}
fn builtinNamesForKind(kind: BuildKind, tool_set: tool_set_contract.ToolSet) ?[]const []const u8 { return switch (kind) { .full => null, .read_only => tool_set.read_only_tool_names, };}
fn toolNameInSet(names: []const []const u8, needle: []const u8) bool { for (names) |name| { if (std.mem.eql(u8, name, needle)) return true; } return false;}
fn isCanonicalToolName(tool_set: tool_set_contract.ToolSet, name: []const u8) bool { for (tool_set.order) |tool_name| { if (std.mem.eql(u8, tool_name, name)) return true; } return false;}
fn expectContainsName(names: []const []const u8, expected: []const u8) !void { for (names) |name| { if (std.mem.eql(u8, name, expected)) return; } return error.TestExpectedEqual;}
fn expectNotContainsName(names: []const []const u8, expected: []const u8) !void { for (names) |name| { if (std.mem.eql(u8, name, expected)) return error.TestExpectedEqual; }}
test "provider-executed search follows settled advertisement permission" { const cases = [_]struct { action: ?types.PermissionAction, advertised: bool, }{ .{ .action = null, .advertised = true }, .{ .action = .allow, .advertised = true }, .{ .action = .ask, .advertised = false }, .{ .action = .deny, .advertised = false }, };
for (cases) |case| { var rules = [_]types.PermissionRule{.{ .permission = @constCast("web_search"), .pattern = @constCast("*"), .action = case.action orelse .deny, }}; const options: Options = if (case.action != null) .{ .permission_rules = .{ .rules = &rules } } else .{}; var projection = try buildTestModelToolProjection(std.testing.allocator, options); defer projection.deinit(std.testing.allocator);
try std.testing.expectEqual( case.advertised, containsName(projection.advertised_names, "web_search"), ); try std.testing.expectEqualStrings( if (case.advertised) test_web_search.description else "", projection.custom_guidance, ); }}
test "provider execution gate follows the registry declaration" { const tools = [_]tool_dispatch.Tool{test_mirror_provider_tool}; inline for (.{ .{ types.PermissionAction.allow, true }, .{ types.PermissionAction.ask, false }, .{ types.PermissionAction.deny, false }, }) |case| { var rules = [_]types.PermissionRule{.{ .permission = @constCast("mirror_search"), .pattern = @constCast("*"), .action = case[0], }}; var projection = try buildTestModelToolProjectionForRegistry( std.testing.allocator, &tools, .{ .permission_rules = .{ .rules = &rules } }, ); defer projection.deinit(std.testing.allocator); try std.testing.expectEqual(case[1], containsName(projection.advertised_names, "mirror_search")); }}
test "ask keeps advertising locally executed tools" { const tools = [_]tool_dispatch.Tool{test_web_search_base}; var rules = [_]types.PermissionRule{.{ .permission = @constCast("web_search"), .pattern = @constCast("*"), .action = .ask, }}; var projection = try buildTestModelToolProjectionForRegistry( std.testing.allocator, &tools, .{ .permission_rules = .{ .rules = &rules } }, ); defer projection.deinit(std.testing.allocator); try expectContainsName(projection.advertised_names, "web_search");}
test "yolo advertisement ignores permission filtering" { var rules = [_]types.PermissionRule{.{ .permission = @constCast("*"), .pattern = @constCast("*"), .action = .deny, }}; var projection = try buildTestModelToolProjection(std.testing.allocator, .{ .permission_mode = .yolo, .permission_rules = .{ .rules = &rules }, }); defer projection.deinit(std.testing.allocator); try expectContainsName(projection.advertised_names, "shell"); try expectContainsName(projection.advertised_names, "write_file"); try expectContainsName(projection.advertised_names, "web_search");}
test "category-wide denies and later overrides select the expected tools" { var denied_rules = [_]types.PermissionRule{.{ .permission = @constCast("edit"), .pattern = @constCast("*"), .action = .deny, }}; var denied = try buildTestModelToolProjection(std.testing.allocator, .{ .permission_rules = .{ .rules = &denied_rules }, }); defer denied.deinit(std.testing.allocator); try expectNotContainsName(denied.advertised_names, "edit_file"); try expectNotContainsName(denied.advertised_names, "write_file");
var overridden_rules = [_]types.PermissionRule{ .{ .permission = @constCast("edit"), .pattern = @constCast("*"), .action = .deny }, .{ .permission = @constCast("edit"), .pattern = @constCast("src/*"), .action = .ask }, }; var overridden = try buildTestModelToolProjection(std.testing.allocator, .{ .permission_rules = .{ .rules = &overridden_rules }, }); defer overridden.deinit(std.testing.allocator); try expectContainsName(overridden.advertised_names, "edit_file"); try expectContainsName(overridden.advertised_names, "write_file");}
fn checkEffectiveToolProjectionAllocationFailures(alloc: Allocator) !void { var projection = buildTestModelToolProjection(alloc, .{}) catch |err| return switch (err) { error.WriteFailed => error.OutOfMemory, else => err, }; defer projection.deinit(alloc); try expectContainsName(projection.advertised_names, "read_file"); try std.testing.expectEqualStrings(test_web_search.description, projection.custom_guidance);}
test "effective tool projection cleans up every partial allocation failure" { try std.testing.checkAllAllocationFailures( std.testing.allocator, checkEffectiveToolProjectionAllocationFailures, .{}, );}
test "base tool projection includes MCP discovery and explicit selection" { const alloc = std.testing.allocator; var projection = try buildTestModelToolProjection(alloc, .{}); defer projection.deinit(alloc); try expectContainsName(projection.advertised_names, "capability_search"); try expectContainsName(projection.advertised_names, "mcp_select_tool");}
test "subagent and shell selection follow host capability" { var unavailable = try buildTestModelToolProjection(std.testing.allocator, .{}); defer unavailable.deinit(std.testing.allocator); try expectNotContainsName(unavailable.advertised_names, "subagent"); try expectNotContainsName(unavailable.advertised_names, "task"); try expectContainsName(unavailable.advertised_names, "shell");
var available = try buildTestModelToolProjection(std.testing.allocator, .{ .subagent_available = true, }); defer available.deinit(std.testing.allocator); try expectContainsName(available.advertised_names, "subagent"); try expectNotContainsName(available.advertised_names, "task"); try expectContainsName(available.advertised_names, "shell");}