Build the loop once by hand
Before you use any framework, build the loop yourself. Not because frameworks are bad, but because frameworks hide the thing you must understand. The provider returns either final text or tool calls. Your application executes tool calls and feeds the results back. That is the machine.
A hand-built loop teaches the three failure points frameworks cannot save you from: bad tool schemas, bad tool result formatting, and missing stop policies.
The loop shape
Start with a message list. Send it to the model with tool definitions. If the model returns tool calls, execute them in your trusted code. Append the model's tool request and your tool result to state. Repeat.
The implementation below is intentionally provider-neutral. Real APIs differ in message shape, but the control flow is the same.
Keep tool execution outside the model
The model requests a tool call; your application decides whether it is allowed, executes it, catches errors, logs it, and returns a concise result. That separation is what keeps the system debuggable and permissioned.