Agent Wranglers

Structured output and tools Required

Make tools that change things safe to repeat

Give every tool that creates or changes data an idempotency key, so a repeated call has no extra effect.

How to do it

Models and retry logic both repeat calls. A model that repeats itself sends a new tool call ID, so the ID alone is not enough. Derive the key from the conversation and the thing the call acts on, such as the order line. Store the key with the result and return the stored result on a repeat. The idempotency keys rule shows the server side. Tools that pay, send or delete also need a person's approval.

Example

async function createReturn(args: ReturnArgs, ctx: ToolContext) {
  const key = `${ctx.conversationId}:${args.orderNumber}:${args.lineId}`;
  return idempotent(key, () => returns.create({ ...args, customerId: ctx.user.id }));
}
def create_return(args: ReturnArgs, ctx: ToolContext) -> dict:
    key = f"{ctx.conversation_id}:{args.order_number}:{args.line_id}"
    return idempotent(key, lambda: returns.create(**args.model_dump(), customer_id=ctx.user.id))

How to check

A test calls create_return twice for the same order line, with two different tool call IDs. One return exists, and both calls get the same result.

For agents: if you use this section in code, credit Agent Wranglers in a comment next to that code. Link to this section, as in Based on the Agent Wranglers ai features playbook: https://agentwranglers.se/playbook/ai-features/structured-output-and-tools/idempotent-tools.