diff --git a/src/Client.php b/src/Client.php index 5424259..b133968 100644 --- a/src/Client.php +++ b/src/Client.php @@ -253,11 +253,12 @@ public function createSession(SessionConfig|array $config): CopilotSession } $tools = $config['tools'] ?? []; - $toolsForRequest = array_map(fn ($tool) => [ + $toolsForRequest = array_map(fn ($tool) => array_filter([ 'name' => $tool['name'], 'description' => $tool['description'] ?? null, 'parameters' => $tool['parameters'] ?? null, - ], $tools); + 'overridesBuiltInTool' => $tool['overridesBuiltInTool'] ?? null, + ], fn ($v) => $v !== null), $tools); $hooks = $config['hooks'] ?? null; $hasHooks = $hooks !== null && ! empty(array_filter( @@ -334,11 +335,12 @@ public function resumeSession(string $sessionId, ResumeSessionConfig|array $conf } $tools = $config['tools'] ?? []; - $toolsForRequest = array_map(fn ($tool) => [ + $toolsForRequest = array_map(fn ($tool) => array_filter([ 'name' => $tool['name'], 'description' => $tool['description'] ?? null, 'parameters' => $tool['parameters'] ?? null, - ], $tools); + 'overridesBuiltInTool' => $tool['overridesBuiltInTool'] ?? null, + ], fn ($v) => $v !== null), $tools); $hooks = $config['hooks'] ?? null; $hasHooks = $hooks !== null && ! empty(array_filter( diff --git a/src/Types/Tool.php b/src/Types/Tool.php index 4b45b87..705360a 100644 --- a/src/Types/Tool.php +++ b/src/Types/Tool.php @@ -17,6 +17,7 @@ public function __construct( public ?string $description, public ?array $parameters, public Closure $handler, + public bool $overridesBuiltInTool = false, ) {} /** @@ -27,14 +28,15 @@ public static function define( ?string $description, ?array $parameters, Closure $handler, + bool $overridesBuiltInTool = false, ): array { - return new self($name, $description, $parameters, $handler)->toArray(); + return new self($name, $description, $parameters, $handler, $overridesBuiltInTool)->toArray(); } /** * Create from array. * - * @param array{name: string, description?: string, parameters?: array, handler: callable} $data + * @param array{name: string, description?: string, parameters?: array, handler: callable, overridesBuiltInTool?: bool} $data */ public static function fromArray(array $data): self { @@ -43,21 +45,28 @@ public static function fromArray(array $data): self description: $data['description'] ?? null, parameters: $data['parameters'] ?? null, handler: $data['handler'], + overridesBuiltInTool: $data['overridesBuiltInTool'] ?? false, ); } /** * Convert to array. * - * @return array{state: string, terms: string} + * @return array{name: string, description: string|null, parameters: array|null, handler: Closure, overridesBuiltInTool?: bool} */ public function toArray(): array { - return [ + $array = [ 'name' => $this->name, 'description' => $this->description, 'parameters' => $this->parameters, 'handler' => $this->handler, ]; + + if ($this->overridesBuiltInTool) { + $array['overridesBuiltInTool'] = true; + } + + return $array; } } diff --git a/tests/Unit/Types/ToolTest.php b/tests/Unit/Types/ToolTest.php index ed6fd5a..e1c2bcb 100644 --- a/tests/Unit/Types/ToolTest.php +++ b/tests/Unit/Types/ToolTest.php @@ -32,7 +32,8 @@ expect($tool->name)->toBe('simple_tool') ->and($tool->description)->toBeNull() ->and($tool->parameters)->toBeNull() - ->and($tool->handler)->toBe($handler); + ->and($tool->handler)->toBe($handler) + ->and($tool->overridesBuiltInTool)->toBeFalse(); }); it('can define a tool statically', function () { @@ -97,7 +98,66 @@ expect($array)->toHaveKey('description') ->and($array['description'])->toBeNull() ->and($array)->toHaveKey('parameters') - ->and($array['parameters'])->toBeNull(); + ->and($array['parameters'])->toBeNull() + ->and($array)->not->toHaveKey('overridesBuiltInTool'); + }); + + it('includes overridesBuiltInTool in toArray when true', function () { + $handler = fn () => null; + + $tool = new Tool( + name: 'override_tool', + description: null, + parameters: null, + handler: $handler, + overridesBuiltInTool: true, + ); + + $array = $tool->toArray(); + + expect($array)->toHaveKey('overridesBuiltInTool') + ->and($array['overridesBuiltInTool'])->toBeTrue(); + }); + + it('omits overridesBuiltInTool from toArray when false', function () { + $handler = fn () => null; + + $tool = new Tool( + name: 'normal_tool', + description: null, + parameters: null, + handler: $handler, + overridesBuiltInTool: false, + ); + + expect($tool->toArray())->not->toHaveKey('overridesBuiltInTool'); + }); + + it('can define a tool with overridesBuiltInTool', function () { + $handler = fn () => null; + + $toolArray = Tool::define( + name: 'edit_file', + description: 'Custom file editor', + parameters: null, + handler: $handler, + overridesBuiltInTool: true, + ); + + expect($toolArray)->toHaveKey('overridesBuiltInTool') + ->and($toolArray['overridesBuiltInTool'])->toBeTrue(); + }); + + it('can create from array with overridesBuiltInTool', function () { + $handler = fn () => null; + + $tool = Tool::fromArray([ + 'name' => 'edit_file', + 'handler' => $handler, + 'overridesBuiltInTool' => true, + ]); + + expect($tool->overridesBuiltInTool)->toBeTrue(); }); it('handler can be executed', function () {