-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathClosureTool.php
More file actions
109 lines (86 loc) · 2.8 KB
/
ClosureTool.php
File metadata and controls
109 lines (86 loc) · 2.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
<?php
declare(strict_types=1);
namespace Cortex\Tools;
use Closure;
use ReflectionFunction;
use Cortex\Attributes\Tool;
use Cortex\LLM\Data\ToolCall;
use Cortex\JsonSchema\SchemaFactory;
use Cortex\JsonSchema\Support\DocParser;
use Cortex\JsonSchema\Types\ObjectSchema;
class ClosureTool extends AbstractTool
{
protected ReflectionFunction $reflection;
protected ObjectSchema $schema;
public function __construct(
protected Closure $closure,
protected ?string $name = null,
protected ?string $description = null,
) {
$this->reflection = new ReflectionFunction($closure);
$this->schema = SchemaFactory::fromClosure($closure);
}
public function name(): string
{
return $this->name ?? $this->resolveName();
}
public function description(): string
{
return $this->description ?? $this->resolveDescription();
}
public function schema(): ObjectSchema
{
return $this->schema;
}
/**
* @param ToolCall|array<string, mixed> $toolCall
*/
public function invoke(ToolCall|array $toolCall = []): mixed
{
// Get the arguments from the given tool call.
$arguments = $this->getArguments($toolCall);
// Ensure arguments are valid as per the tool's schema.
$this->schema->validate($arguments);
// Invoke the closure with the arguments.
return $this->reflection->invokeArgs($arguments);
}
/**
* Attempt to resolve the name of the tool from the Tool attribute,
* or the name of the closure if no Tool attribute is present.
*/
protected function resolveName(string $default = 'closure'): string
{
$parameters = $this->getToolAttributeParameters();
return $parameters['name'] ?? $default;
}
/**
* Attempt to resolve the description of the tool from the Tool attribute,
* or the docblock of the closure if no Tool attribute is present.
*/
protected function resolveDescription(string $default = ''): string
{
$parameters = $this->getToolAttributeParameters();
if (is_array($parameters)) {
return $parameters['description'];
}
$docblock = $this->reflection->getDocComment();
if ($docblock === false) {
return $default;
}
$docParser = new DocParser($docblock);
return $docParser->description() ?? $default;
}
/**
* Get the parameters from the Tool attribute.
*
* @return array{name: string, description: string}|null
*/
protected function getToolAttributeParameters(): ?array
{
$attributes = $this->reflection->getAttributes(Tool::class);
if (isset($attributes[0])) {
return $attributes[0]->getArguments();
}
return null;
}
}