Ir al contenido principal
Laravel, thinking fast.

Validado no es lo mismo que listo. La API de destino rechaza una carga que lleva las dos formas a la vez, así que la herramienta quita las que no aplican:

private function shapeCategoryPayload(array $validated): array
{
    $category = $validated['category'] ?? 'business';

    if ($category !== 'event') {
        foreach (['event_start_at', 'event_end_at', 'event_timezone', /**/] as $key) {
            unset($validated[$key]);
        }

        return $validated;
    }

    $event = [
        'start_at' => $validated['event_start_at'],
        'end_at' => $validated['event_end_at'],
        'timezone' => $validated['event_timezone'],
    ];

    // Business fields are meaningless on an event site and the event
    // template has no partials for them.
    foreach (['services', 'address', 'phone', 'hours'] as $key) {
        unset($validated[$key]);
    }

    $validated['event'] = $event;

    return $validated;
}

Un modelo al que se le han explicado ambas categorías enviará de vez en cuando un campo de la equivocada —no a menudo, pero sí en una cola larga de conversaciones. Limpiar en la frontera hace que eso nunca se convierta en un 422 aguas abajo que el modelo tenga luego que interpretar y del que tenga que recuperarse.

Absorbe el desorden del modelo en tu borde. Es barato aquí y caro tres servicios más allá.

Normaliza la salida, nombra las claves a la defensiva

Lo que devuelve una herramienta se consume dos veces: por el modelo y por lo que sea que lo renderice. A ambos les viene bien una forma que no varíe nunca.

// Normalised here rather than in the client so every consumer of this tool
// gets the same shape, and so a missing description collapses to an empty
// string instead of an undefined key in a Blade template.
$normalised = array_values(array_map(fn (array $option): array => [
    'label' => trim((string) $option['label']),
    'description' => trim((string) ($option['description'] ?? '')),
], $options));

Un campo opcional es opcional para el modelo y obligatorio para tu plantilla. Rellénalo aquí, una vez, en lugar de defenderte de su ausencia en cada consumidor.

La clave del resultado se elige con la misma desconfianza:

// The key the client keys off. Named for what it is rather than reusing
// 'options', which is common enough in tool payloads that a future tool
// could collide with it by accident.
return Response::json([
    'options_prompt' => [ /**/ ],
    'message' => 'Options shown to the user as tappable cards. Wait for their reply — do not repeat the options as text.',
]);

Como el frontend ramifica según qué claves están presentes, una clave genérica como options es una colisión esperando a la segunda herramienta que tenga opciones. Nombra las claves de resultado por la herramienta que las produjo.