Files
WP-LIT-MCP/src/Abilities/ToolResult.php
T

189 lines
5.3 KiB
PHP

<?php
declare(strict_types=1);
namespace LIT\MCP\Abilities;
use InvalidArgumentException;
/**
* Uniform success result of every writing ability (spec §8.1).
* The adapter returns it as structuredContent plus JSON text.
*/
final class ToolResult
{
private const RESERVED = [
'ok', 'summary', 'changed', 'outline', 'rev', 'warnings',
'revision_id', 'snapshot_id', 'log_id', 'preview_url', 'edit_url',
];
/** @var list<array{id: string, type: string, action: string, label: string}> */
private array $changed = [];
/** @var list<string> */
private array $warnings = [];
private ?string $outline = null;
private ?string $rev = null;
private ?int $revisionId = null;
private ?string $snapshotId = null;
private ?int $logId = null;
private ?string $previewUrl = null;
private ?string $editUrl = null;
/** @var array<string, mixed> */
private array $extra = [];
private function __construct(private string $summary)
{
}
public static function ok(string $summary): self
{
return new self($summary);
}
public function changed(string $id, string $type, string $action, string $label = ''): self
{
$this->changed[] = ['id' => $id, 'type' => $type, 'action' => $action, 'label' => $label];
return $this;
}
public function warning(string $warning): self
{
$this->warnings[] = $warning;
return $this;
}
/** @param list<string> $warnings */
public function warnings(array $warnings): self
{
foreach ($warnings as $warning) {
$this->warning($warning);
}
return $this;
}
public function outline(?string $outline): self
{
$this->outline = $outline;
return $this;
}
public function rev(?string $rev): self
{
$this->rev = $rev;
return $this;
}
public function revisionId(?int $revisionId): self
{
$this->revisionId = $revisionId;
return $this;
}
public function snapshotId(?string $snapshotId): self
{
$this->snapshotId = $snapshotId;
return $this;
}
public function logId(?int $logId): self
{
$this->logId = $logId;
return $this;
}
public function urls(?string $previewUrl, ?string $editUrl): self
{
$this->previewUrl = $previewUrl === '' ? null : $previewUrl;
$this->editUrl = $editUrl === '' ? null : $editUrl;
return $this;
}
public function with(string $key, mixed $value): self
{
if (in_array($key, self::RESERVED, true)) {
throw new InvalidArgumentException(sprintf('ToolResult key "%s" is reserved.', $key));
}
$this->extra[$key] = $value;
return $this;
}
/** @return array<string, mixed> */
public function toArray(): array
{
return array_merge(
[
'ok' => true,
'summary' => $this->summary,
'changed' => $this->changed,
'outline' => $this->outline,
'rev' => $this->rev,
'warnings' => $this->warnings,
'revision_id' => $this->revisionId,
'snapshot_id' => $this->snapshotId,
'log_id' => $this->logId,
'preview_url' => $this->previewUrl,
'edit_url' => $this->editUrl,
],
$this->extra
);
}
/**
* @param array<string, array<string, mixed>> $extraProperties
* @param list<string> $extraRequired
* @return array<string, mixed>
*/
public static function schema(array $extraProperties = [], array $extraRequired = []): array
{
return [
'type' => 'object',
'properties' => array_merge(
[
'ok' => ['type' => 'boolean'],
'summary' => ['type' => 'string'],
'changed' => [
'type' => 'array',
'items' => [
'type' => 'object',
'properties' => [
'id' => ['type' => 'string'],
'type' => ['type' => 'string'],
'action' => ['type' => 'string'],
'label' => ['type' => 'string'],
],
'required' => ['id', 'type', 'action', 'label'],
],
],
'outline' => ['type' => ['string', 'null']],
'rev' => ['type' => ['string', 'null']],
'warnings' => ['type' => 'array', 'items' => ['type' => 'string']],
'revision_id' => ['type' => ['integer', 'null']],
'snapshot_id' => ['type' => ['string', 'null']],
'log_id' => ['type' => ['integer', 'null']],
'preview_url' => ['type' => ['string', 'null']],
'edit_url' => ['type' => ['string', 'null']],
],
$extraProperties
),
'required' => array_merge(
['ok', 'summary', 'changed', 'warnings', 'rev', 'revision_id', 'log_id'],
$extraRequired
),
];
}
}