Skip to content

Commit b87c37c

Browse files
committed
Merge branch 'main' into feature/docs
2 parents f5ebc8b + 52513de commit b87c37c

File tree

8 files changed

+587
-49
lines changed

8 files changed

+587
-49
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,4 @@ composer.lock
1111
phpunit.xml
1212
phpcs.xml
1313
.phpcs.xml
14+
.vscode/

src/AiCommand.php

Lines changed: 23 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
namespace WP_CLI\AiCommand;
44

5+
use WP_CLI\AiCommand\Tools\FileTools;
6+
use WP_CLI\AiCommand\Tools\URLTools;
57
use WP_CLI;
68
use WP_CLI_Command;
79
use WP_Community_Events;
@@ -20,6 +22,7 @@
2022
* Servers provide context, tools, and prompts to clients
2123
*/
2224
class AiCommand extends WP_CLI_Command {
25+
2326
/**
2427
* Greets the world.
2528
*
@@ -60,51 +63,35 @@ public function __invoke( $args, $assoc_args ) {
6063
private function register_tools($server, $client) {
6164
$server->register_tool(
6265
[
63-
'name' => 'calculate_total',
64-
'description' => 'Calculates the total price.',
66+
'name' => 'list_tools',
67+
'description' => 'Lists all available tools with their descriptions.',
6568
'inputSchema' => [
66-
'type' => 'object',
67-
'properties' => [
68-
'price' => [
69-
'type' => 'integer',
70-
'description' => 'The price of the item.',
69+
'type' => 'object', // Object type for input
70+
'properties' => [
71+
'placeholder' => [
72+
'type' => 'integer',
73+
'description' => '',
74+
]
7175
],
72-
'quantity' => [
73-
'type' => 'integer',
74-
'description' => 'The quantity of items.',
75-
],
76-
],
77-
'required' => [ 'price', 'quantity' ],
76+
'required' => [], // No required fields
7877
],
79-
'callable' => function ( $params ) {
80-
$price = $params['price'] ?? 0;
81-
$quantity = $params['quantity'] ?? 1;
78+
'callable' => function () use ($server) {
79+
// Get all capabilities
80+
$capabilities = $server->get_capabilities();
8281

83-
return $price * $quantity;
84-
},
85-
]
86-
);
82+
// Prepare a list of tools with their descriptions
83+
$tool_list = 'Return this to the user as a bullet list with each tool name and description on a new line. \n\n';
84+
$tool_list .= print_r($capabilities['methods'], true);
8785

88-
$server->register_tool(
89-
[
90-
'name' => 'greet',
91-
'description' => 'Greets the user.',
92-
'inputSchema' => [
93-
'type' => 'object',
94-
'properties' => [
95-
'name' => [
96-
'type' => 'string',
97-
'description' => 'The name of the user.',
98-
],
99-
],
100-
'required' => [ 'name' ],
101-
],
102-
'callable' => function ( $params ) {
103-
return 'Hello, ' . $params['name'] . '!';
86+
// Return the formatted string of tools with descriptions
87+
return $tool_list;
10488
},
10589
]
10690
);
10791

92+
$map_rest_to_mcp = new MapRESTtoMCP();
93+
$map_rest_to_mcp->map_rest_to_mcp( $server );
94+
10895
$server->register_tool(
10996
[
11097
'name' => 'generate_image',
@@ -213,7 +200,6 @@ private function register_tools($server, $client) {
213200
},
214201
]
215202
);
216-
217203
}
218204

219205
// Register resources for AI access

src/MCP/Client.php

Lines changed: 73 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,14 @@
66
use Felix_Arntz\AI_Services\Services\API\Enums\AI_Capability;
77
use Felix_Arntz\AI_Services\Services\API\Enums\Content_Role;
88
use Felix_Arntz\AI_Services\Services\API\Helpers;
9+
use Felix_Arntz\AI_Services\Services\API\Types\Blob;
910
use Felix_Arntz\AI_Services\Services\API\Types\Content;
1011
use Felix_Arntz\AI_Services\Services\API\Types\Parts;
1112
use Felix_Arntz\AI_Services\Services\API\Types\Parts\File_Data_Part;
1213
use Felix_Arntz\AI_Services\Services\API\Types\Parts\Function_Call_Part;
1314
use Felix_Arntz\AI_Services\Services\API\Types\Parts\Inline_Data_Part;
1415
use Felix_Arntz\AI_Services\Services\API\Types\Parts\Text_Part;
16+
use Felix_Arntz\AI_Services\Services\API\Types\Text_Generation_Config;
1517
use Felix_Arntz\AI_Services\Services\API\Types\Tools;
1618
use WP_CLI;
1719

@@ -128,11 +130,23 @@ static function () {
128130
}
129131

130132
public function call_ai_service_with_prompt( string $prompt ) {
133+
\WP_CLI::debug( "Prompt: {$prompt}", 'mcp_server' );
131134
$parts = new Parts();
132135
$parts->add_text_part( $prompt );
133-
$content = new Content( Content_Role::USER, $parts );
134136

135-
return $this->call_ai_service( [ $content ] );
137+
$contents = [
138+
new Content( Content_Role::USER, $parts ),
139+
];
140+
141+
// $parts = new Parts();
142+
// $parts->add_inline_data_part(
143+
// 'image/png',
144+
// Helpers::blob_to_base64_data_url( new Blob( file_get_contents( '/private/tmp/ai-generated-imaget1sjmomi30i31C1YtZy.png' ), 'image/png' ) ),
145+
// );
146+
//
147+
// $contents[] = $parts;
148+
149+
return $this->call_ai_service( $contents );
136150
}
137151

138152
private function call_ai_service( $contents ) {
@@ -172,7 +186,7 @@ static function () {
172186
]
173187
);
174188

175-
\WP_CLI::debug( 'Making request...' . print_r( $contents, true ), 'ai' );
189+
\WP_CLI::debug( 'Making request...' . print_r( $contents, true ), 'ai' );
176190

177191
if ( $service->get_service_slug() === 'openai' ) {
178192
$model = 'gpt-4o';
@@ -183,14 +197,22 @@ static function () {
183197
$candidates = $service
184198
->get_model(
185199
[
186-
'feature' => 'text-generation',
187-
'model' => $model,
188-
'tools' => $tools,
189-
'capabilities' => [
190-
AI_Capability::MULTIMODAL_INPUT,
191-
AI_Capability::TEXT_GENERATION,
192-
AI_Capability::FUNCTION_CALLING,
193-
],
200+
'feature' => 'text-generation',
201+
'model' => $model,
202+
'tools' => $tools,
203+
'capabilities' => [
204+
AI_Capability::MULTIMODAL_INPUT,
205+
AI_Capability::TEXT_GENERATION,
206+
AI_Capability::FUNCTION_CALLING,
207+
],
208+
// 'generationConfig' => Text_Generation_Config::from_array(
209+
// array(
210+
// 'responseModalities' => array(
211+
// 'Text',
212+
// 'Image',
213+
// ),
214+
// )
215+
// ),
194216
]
195217
)
196218
->generate_text( $contents );
@@ -224,6 +246,46 @@ static function () {
224246
$parts->add_function_response_part( $part->get_id(), $part->get_name(), $function_result );
225247
$content = new Content( Content_Role::USER, $parts );
226248
$new_contents[] = $content;
249+
} elseif ( $part instanceof Inline_Data_Part ) {
250+
$image_url = $part->get_base64_data(); // Data URL.
251+
$image_blob = Helpers::base64_data_url_to_blob( $image_url );
252+
253+
if ( $image_blob ) {
254+
$filename = tempnam( '/tmp', 'ai-generated-image' );
255+
$parts = explode( '/', $part->get_mime_type() );
256+
$extension = $parts[1];
257+
rename( $filename, $filename . '.' . $extension );
258+
$filename .= '.' . $extension;
259+
260+
file_put_contents( $filename, $image_blob->get_binary_data() );
261+
262+
$image_url = $filename;
263+
} else {
264+
$binary_data = base64_decode( $image_url );
265+
if ( false !== $binary_data ) {
266+
$image_blob = new Blob( $binary_data, $part->get_mime_type() );
267+
268+
$filename = tempnam( '/tmp', 'ai-generated-image' );
269+
$parts = explode( '/', $part->get_mime_type() );
270+
$extension = $parts[1];
271+
rename( $filename, $filename . '.' . $extension );
272+
$filename .= '.' . $extension;
273+
274+
file_put_contents( $filename, $image_blob->get_binary_data() );
275+
276+
$image_url = $filename;
277+
}
278+
}
279+
280+
$text .= "Generated image: $image_url\n";
281+
282+
break;
283+
}
284+
285+
if ( $part instanceof File_Data_Part ) {
286+
$image_url = $part->get_file_uri(); // Actual URL. May have limited TTL (often 1 hour).
287+
// TODO: Save as file or so.
288+
break;
227289
}
228290
}
229291

src/MCP/Server.php

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace WP_CLI\AiCommand\MCP;
44

55
use Exception;
6+
use WP_CLI;
67
use InvalidArgumentException;
78

89
class Server {
@@ -49,6 +50,12 @@ public function register_tool( array $tool_definition ): void {
4950
$description = $tool_definition['description'] ?? null;
5051
$input_schema = $tool_definition['inputSchema'] ?? null;
5152

53+
// TODO: This is a temporary limit.
54+
if ( count( $this->tools ) >= 128 ) {
55+
WP_CLI::debug( 'Too many tools, max is 128', 'tools' );
56+
return;
57+
}
58+
5259
$this->tools[ $name ] = [
5360
'name' => $name,
5461
'callable' => $callable,
@@ -163,7 +170,7 @@ public function handle_request( string $request_data ): false|string {
163170
}
164171
}
165172

166-
private function list_resources() {
173+
public function list_resources() {
167174
$result = [];
168175
foreach ( $this->resources as $resource ) {
169176
$result[] = [

0 commit comments

Comments
 (0)