php-agentic/Mcp/Tools/Agent/Plan/PlanCreate.php
2026-01-27 00:28:29 +00:00

144 lines
4.5 KiB
PHP

<?php
declare(strict_types=1);
namespace Core\Agentic\Mcp\Tools\Agent\Plan;
use Core\Mod\Mcp\Dependencies\ToolDependency;
use Illuminate\Support\Str;
use Core\Agentic\Mcp\Tools\Agent\AgentTool;
use Core\Agentic\Models\AgentPhase;
use Core\Agentic\Models\AgentPlan;
/**
* Create a new work plan with phases and tasks.
*/
class PlanCreate extends AgentTool
{
protected string $category = 'plan';
protected array $scopes = ['write'];
/**
* Get the dependencies for this tool.
*
* @return array<ToolDependency>
*/
public function dependencies(): array
{
return [
ToolDependency::contextExists('workspace_id', 'Workspace context required'),
];
}
public function name(): string
{
return 'plan_create';
}
public function description(): string
{
return 'Create a new work plan with phases and tasks';
}
public function inputSchema(): array
{
return [
'type' => 'object',
'properties' => [
'title' => [
'type' => 'string',
'description' => 'Plan title',
],
'slug' => [
'type' => 'string',
'description' => 'URL-friendly identifier (auto-generated if not provided)',
],
'description' => [
'type' => 'string',
'description' => 'Plan description',
],
'context' => [
'type' => 'object',
'description' => 'Additional context (related files, dependencies, etc.)',
],
'phases' => [
'type' => 'array',
'description' => 'Array of phase definitions with name, description, and tasks',
'items' => [
'type' => 'object',
'properties' => [
'name' => ['type' => 'string'],
'description' => ['type' => 'string'],
'tasks' => [
'type' => 'array',
'items' => ['type' => 'string'],
],
],
],
],
],
'required' => ['title'],
];
}
public function handle(array $args, array $context = []): array
{
try {
$title = $this->requireString($args, 'title', 255);
$slug = $this->optionalString($args, 'slug', null, 255) ?? Str::slug($title).'-'.Str::random(6);
$description = $this->optionalString($args, 'description', null, 10000);
} catch (\InvalidArgumentException $e) {
return $this->error($e->getMessage());
}
if (AgentPlan::where('slug', $slug)->exists()) {
return $this->error("Plan with slug '{$slug}' already exists");
}
// Determine workspace_id - never fall back to hardcoded value in multi-tenant environment
$workspaceId = $context['workspace_id'] ?? null;
if ($workspaceId === null) {
return $this->error('workspace_id is required but could not be determined from context');
}
$plan = AgentPlan::create([
'slug' => $slug,
'title' => $title,
'description' => $description,
'status' => 'draft',
'context' => $args['context'] ?? [],
'workspace_id' => $workspaceId,
]);
// Create phases if provided
if (! empty($args['phases'])) {
foreach ($args['phases'] as $order => $phaseData) {
$tasks = collect($phaseData['tasks'] ?? [])->map(fn ($task) => [
'name' => $task,
'status' => 'pending',
])->all();
AgentPhase::create([
'agent_plan_id' => $plan->id,
'name' => $phaseData['name'],
'description' => $phaseData['description'] ?? null,
'order' => $order + 1,
'status' => 'pending',
'tasks' => $tasks,
]);
}
}
$plan->load('agentPhases');
return $this->success([
'plan' => [
'slug' => $plan->slug,
'title' => $plan->title,
'status' => $plan->status,
'phases' => $plan->agentPhases->count(),
],
]);
}
}