Da forma a la carga en la frontera
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.