Skip to content

Commit eb77aca

Browse files
committed
toolkit
1 parent 4e728da commit eb77aca

File tree

5 files changed

+76
-75
lines changed

5 files changed

+76
-75
lines changed

src/Support/helpers.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
* Helper function to create a chat prompt builder.
2020
*
2121
* @param MessageCollection|array<int, \Cortex\LLM\Contracts\Message>|string|null $messages
22+
*
23+
* @return ($messages is null ? \Cortex\Prompts\Prompt : ($messages is string ? \Cortex\Prompts\Builders\TextPromptBuilder : \Cortex\Prompts\Builders\ChatPromptBuilder))
2224
*/
2325
function prompt(MessageCollection|array|string|null $messages): Prompt|PromptBuilder
2426
{

src/Tools/McpTool.php

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,17 +24,22 @@ class McpTool extends AbstractTool
2424

2525
public function __construct(
2626
protected string $name,
27-
protected ?string $mcpServer = null,
27+
protected ?string $server = null,
28+
protected ?ToolDefinition $toolDefinition = null,
2829
) {
29-
$this->client = McpServer::driver($this->mcpServer);
30-
$toolDefinition = $this->getToolDefinition();
31-
$this->description = $toolDefinition->description ?? '';
32-
$schema = SchemaFactory::fromJson($toolDefinition->inputSchema);
30+
$this->client = McpServer::driver($this->server);
31+
32+
// If a tool definition is provided then we don't need to connect to the MCP server yet.
33+
$this->toolDefinition ??= $this->getToolDefinition();
34+
35+
$schema = SchemaFactory::from($this->toolDefinition->inputSchema);
3336

3437
if (! $schema instanceof ObjectSchema) {
3538
throw new GenericException(sprintf('Schema for tool %s is not an object', $this->name));
3639
}
3740

41+
$this->description = $this->toolDefinition->description ?? '';
42+
3843
if ($toolDefinition->description !== null) {
3944
$schema->description($toolDefinition->description);
4045
}
@@ -68,7 +73,7 @@ public function invoke(ToolCall|array $toolCall = []): mixed
6873
// Get the arguments from the given tool call.
6974
$arguments = $this->getArguments($toolCall);
7075

71-
// Ensure arguments are valid as per the tool's schema.
76+
// Ensure arguments are valid as per the tool's schema (if it has properties).
7277
if ($this->schema->getPropertyKeys() !== []) {
7378
$this->schema->validate($arguments);
7479
}
@@ -94,7 +99,7 @@ protected function getToolDefinition(): ToolDefinition
9499
$tool = collect($tools)->firstWhere('name', $this->name);
95100

96101
if ($tool === null) {
97-
throw new GenericException(sprintf('Tool %s not found in MCP server %s', $this->name, $this->mcpServer));
102+
throw new GenericException(sprintf('Tool [%s] not found in MCP server [%s]', $this->name, $this->server));
98103
}
99104

100105
return $tool;

src/Tools/ToolKits/McpToolKit.php

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Cortex\Tools\ToolKits;
6+
7+
use Cortex\Tools\McpTool;
8+
use PhpMcp\Client\Client;
9+
use Cortex\Facades\McpServer;
10+
use PhpMcp\Client\Model\Definitions\ToolDefinition;
11+
12+
class McpToolKit
13+
{
14+
protected Client $client;
15+
16+
public function __construct(
17+
protected ?string $server = null,
18+
) {
19+
$this->client = McpServer::driver($this->server);
20+
}
21+
22+
/**
23+
* @return array<array-key, \Cortex\LLM\Contracts\Tool>
24+
*/
25+
public function getTools(): array
26+
{
27+
try {
28+
$this->client->initialize();
29+
$tools = $this->client->listTools();
30+
31+
return collect($tools)
32+
->map(fn(ToolDefinition $toolDefinition): McpTool => new McpTool(
33+
$toolDefinition->name,
34+
$this->server,
35+
$toolDefinition,
36+
))
37+
->all();
38+
39+
} finally {
40+
$this->client->disconnect();
41+
}
42+
}
43+
44+
public function __destruct()
45+
{
46+
$this->client->disconnect();
47+
}
48+
}

tests/Unit/Experimental/PlaygroundTest.php

Lines changed: 0 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,11 @@
55
use Cortex\Cortex;
66
use Cortex\Pipeline;
77
use Cortex\Facades\LLM;
8-
use Cortex\Facades\Image;
9-
use Cortex\Attributes\Tool;
10-
use Cortex\Chat\GenericChat;
118
use Cortex\Facades\ModelInfo;
12-
use Cortex\Memory\ChatMemory;
13-
use Cortex\Facades\Embeddings;
149
use Cortex\Events\ChatModelEnd;
15-
use Cortex\Facades\VectorStore;
1610
use Cortex\Tasks\Enums\TaskType;
1711
use Cortex\Events\ChatModelStart;
1812
use Cortex\JsonSchema\SchemaFactory;
19-
use Cortex\Memory\ChatSummaryMemory;
2013
use Illuminate\Support\Facades\Event;
2114
use Cortex\JsonSchema\Types\StringSchema;
2215
use Cortex\LLM\Data\Messages\UserMessage;
@@ -100,14 +93,6 @@
10093
dd('done');
10194
})->skip();
10295

103-
test('image playground', function (): void {
104-
$generator = Image::driver();
105-
106-
$result = $generator->invoke('A beautiful landscape with a river and mountains');
107-
108-
dd($result);
109-
})->skip();
110-
11196
test('piping tasks with structured output', function (): void {
11297
Event::listen(ChatModelStart::class, function (ChatModelStart $event): void {
11398
dump($event->parameters);
@@ -249,58 +234,6 @@
249234
dd($result);
250235
})->skip();
251236

252-
test('chat', function (): void {
253-
$llm = LLM::provider('openai')->withModel('gpt-4o-mini');
254-
255-
$add = #[Tool(name: 'add', description: 'Add two numbers')]
256-
function (int $a, int $b): int {
257-
return $a + $b;
258-
};
259-
260-
$chat = new GenericChat($llm, new ChatMemory(), tools: [$add]);
261-
262-
$result = $chat->sendMessage(new UserMessage('Hello, my name is Sean, how are you?'));
263-
dump('Result 1: ' . $result->text());
264-
265-
$result = $chat->sendMessage(new UserMessage('What is 2 + 2?'));
266-
dump('Result 2: ' . $result->text());
267-
268-
$result = $chat->sendMessage(new UserMessage('What is my name?'));
269-
dump('Result 3: ' . $result->text());
270-
271-
dd($chat->getMessages());
272-
})->skip();
273-
274-
test('chat summary memory', function (): void {
275-
$summaryLLM = LLM::provider('ollama')->withModel('llama3.2');
276-
$chatLLM = LLM::provider('ollama')->withModel('llama3.1');
277-
278-
$chat = new GenericChat($chatLLM, new ChatSummaryMemory($summaryLLM));
279-
280-
$result = $chat->sendMessage(new UserMessage('Hello, my name is Sean, how are you?'));
281-
dump('Result 1: ' . $result->text());
282-
283-
$result = $chat->sendMessage(new UserMessage('My favourite food is pizza'));
284-
dump('Result 2: ' . $result->text());
285-
286-
$result = $chat->sendMessage(new UserMessage('What is my favourite food?'));
287-
dump('Result 3: ' . $result->text());
288-
})->skip();
289-
290-
test('qdrant', function (): void {
291-
$result = Embeddings::driver('ollama')->invoke([
292-
"The State of the Union Address (sometimes abbreviated to SOTU) is an annual message delivered by the president of the United States to a joint session of the United States Congress near the beginning of most calendar years on the current condition of the nation.[3][4] The State of the Union Address generally includes reports on the nation's budget, economy, news, agenda, progress, achievements and the president's priorities and legislative proposals",
293-
"The address fulfills the requirement in Article II, Section 3, Clause 1 of the U.S. Constitution for the president to periodically \"give to the Congress Information of the State of the Union, and recommend to their Consideration such Measures as he shall judge necessary and expedient.\" During most of the country's first century, the president primarily submitted only a written report to Congress. After 1913, Woodrow Wilson, the 28th U.S. president, began the regular practice of delivering the address to Congress in person as a way to rally support for the president's agenda, while also submitting a more detailed report.[3] With the advent of radio and television, the address is now broadcast live in all United States time zones on many networks.",
294-
'The speech is generally held in January or February, and an invitation to the president is extended to use the chamber of the House by the speaker of the House. Starting in 1981, Ronald Reagan, the 40th U.S. president, began the practice of newly inaugurated presidents delivering an address to Congress in the first year of their term but not designating that speech an official "State of the Union".',
295-
]);
296-
$qdrant = VectorStore::driver('qdrant');
297-
$qdrant->ensureCollectionExists('test', $result->size);
298-
299-
// foreach ($result->embeddings as $embedding) {
300-
// $qdrant->add('test', $embedding);
301-
// }
302-
})->skip();
303-
304237
test('parallel group 1', function (): void {
305238
$dogJoke = task('tell_a_dog_joke', TaskType::Structured)
306239
->system('You are a comedian.')

tests/Unit/Tools/McpToolTest.php

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,12 @@
55
namespace Cortex\Tests\Unit\Tools;
66

77
use Cortex\Tools\McpTool;
8+
use Cortex\Tools\ToolKits\McpToolKit;
89

910
test('it can create a schema from an MCP tool', function (): void {
1011
// $tool = new McpTool(
1112
// name: 'tavily_search',
12-
// mcpServer: 'tavily',
13+
// server: 'tavily',
1314
// );
1415

1516
$tool = new McpTool('echo');
@@ -51,3 +52,15 @@
5152
// ],
5253
// ]);
5354
})->todo();
55+
56+
test('it can create an MCP tool kit', function (): void {
57+
$kit = new McpToolKit();
58+
59+
$tools = collect($kit->getTools());
60+
61+
dd($tools->map(fn(McpTool $tool): array => [
62+
'name' => $tool->name(),
63+
// 'description' => $tool->description(),
64+
'schema' => $tool->schema()->toArray(),
65+
])->all());
66+
})->todo();

0 commit comments

Comments
 (0)