RagLeap
Blog

How to let an AI agent delegate work to sub-agents, with limits and approval rules (ragleap-agents 0.5.0)

Short answer: since ragleap-agents 0.5.0 an agent can hand one task to a named child agent through make_delegate_tool, an ordinary tool. It is opt-in: a run behaves as in 0.4.1 unless you pass tainted=True or build a delegate tool. A child that reaches an action needing approval is stopped, and the action does not run. This guide follows the 0.5.0 changelog. That changelog gives the signatures below but no complete example, so this page shows none rather than invent one.

What does the delegate tool do?

make_delegate_tool(children, *, max_depth=1, budget=None, allow_outbound=False, name="delegate") returns a tool that hands one task to a named child agent and returns its short answer as an untrusted, fenced observation. The model sees the child's answer as data, not as an instruction.

How is it limited?

  • Budget(max_delegations=4, max_child_steps=16) and max_depth limit the depth, the number of delegations and the children's steps per root run. MAX_DEPTH_CEILING = 3. The counters are saved in the root run's state and survive a pause and resume. A child's own step cap bounds how far its steps can overshoot the budget.
  • delegate_policy(children, *, allow_outbound=False) validates the children and returns the ToolPolicy for the delegate tool. It taints if any child tool can taint and is never outbound. A child tool with no declared policy raises, and an outbound one raises unless allow_outbound=True.

What happens when a child needs approval?

Children cannot pause for approval in this release. A child that reaches an action needing approval is stopped with stop_reason="approval_not_available" and the action does not run. A child starts tainted if its parent was.

What is a tainted run?

Agent.run(task, *, tainted=False) can start a run already tainted, so every outbound tool needs approval from the first step, as it does after a tainting tool has run. The flag must be a bool, and it is saved in the run state, so it survives a pause and resume. It is meant for runs whose task comes from an untrusted source (an incoming message, a webhook payload) and for sub-agents started by a tainted parent.

Can a tool see which run it is in?

ragleap_agents.context.current_run() returns the RunContext (run id, depth, taint, counters) of the run executing the current tool call, or None outside a run. It is a context variable, so threads do not share it.

What has been tested?

From the changelog: all 208 tests pass on Python 3.10, and CI is green on 3.10, 3.11 and 3.12 for the delegate-tool change. A live delegation check with one model (Groq, openai/gpt-oss-20b, native mode, 8 runs): the parent delegated in 8 of 8 runs and send_message never ran; in 3 runs the parent proposed it after a child had read the note, and the taint rule held it for approval.

What has not been verified?

  • Prompt-injection resistance through a sub-agent: only 2 of the 8 runs read the injected note without a prompt that asked for an action, and the model proposed no send in either.
  • The child-side stop with a real model, any other provider or model, resuming a run saved by 0.4.x, and a published 0.5.0 wheel on Python 3.11.

Sources

ragleap-agents on PyPI, the changelog, the first agent and approval gates guide and the library page.

Back to the blog