Thanks for the comment, Mihai_LeanZero. Good catch. I covered cancellation, but not the case where a request gets retried or the caller changes their mind while something is already running.
I would keep the task state in the application and track each side effect with its own operation or idempotency ID. If the caller changes the request, move the task to a new revision and ignore any result that comes back from the older one. If a request times out, check the backend before retrying so you do not accidentally create the same booking twice.
The other important part is not saying something succeeded until the backend has actually confirmed it. “I’m booking that now” is very different from “you’re booked for 3pm.”
Really useful point. I’m adding this to the production component table.
Really thorough rundown, especially the component table -- that's the kind of checklist that would have saved some pain on past projects. One thing I didn't see in the tool execution section: what happens when a caller interrupts mid-tool-call and then re-triggers the same intent ("wait, actually book it for 3pm") while the first call is still in flight on the backend. Interruption handling stops the audio, but nothing stops two overlapping tool calls hitting the same booking or charge unless the tool itself is idempotent or the backend tracks a call id per intent. Worth adding to the component list next to cancel semantics -- an interrupted-but-not-cancelled call plus a retried one is a pretty direct path to a double-booked slot.