RagLeap
Blog

How to build an AI agent in Python that asks for approval before it acts (ragleap-agents)

Short answer: ragleap-agents is a small agent loop. The model proposes one action at a time, sees the result, and proposes the next, up to a hard step cap. You pass a policy that says which tools are trusted and which need human approval; a run that needs approval pauses and resumes after a person decides. This guide follows the README of ragleap-agents 0.5.0. The tools themselves come from ragleap-tools.

How do you run a first agent?

The model is a plain function that takes a prompt and returns text. This is the README quickstart:

pip install ragleap-agents
from ragleap_tools import CALCULATOR_TOOL
from ragleap_agents import Agent, Policy, TRUSTED

def my_llm(prompt: str) -> str:
    ...  # call any model, return its text

agent = Agent(
    llm=my_llm,
    tools=[CALCULATOR_TOOL],
    policy=Policy(max_steps=4, tools={"calculator": TRUSTED}),
)
result = agent.run("What is 6 * 7?")
print(result.status, result.answer)
for step in result.steps:  # the transcript: tool, arguments, status, observation
    print(step["tool"], step["arguments"], step["status"])

There is no database. max_steps is the hard step cap.

How do you use a real model?

openai_compatible returns the model function for any provider that speaks the OpenAI chat-completions API. It uses only the standard library, you pass the key in, and the key is never read from the environment or printed.

from ragleap_agents import Agent, Policy, TRUSTED, openai_compatible

tools = [CALCULATOR_TOOL]
llm = openai_compatible(
    "https://api.groq.com/openai/v1", api_key, "openai/gpt-oss-20b",
    mode="native", tools=tools,
)
agent = Agent(llm, tools, Policy(tools={"calculator": TRUSTED}))

https is required, redirects are refused, responses are size-capped, and temporary errors are retried with backoff. Errors carry only a status code or an exception type, never a response body, URL or key. The base URL is yours to set, so do not build it from untrusted input.

How do you make an agent ask for approval first?

Mark a tool as needing approval. The run then stops with the status awaiting_approval and a pending call, and you resume it with a decision. This excerpt from the README assumes my_llm, tools and my_store already exist:

from ragleap_agents import ToolPolicy

policy = Policy(tools={"write_file": ToolPolicy(taints=False, outbound=True, requires_approval=True)})
agent = Agent(my_llm, tools, policy, store=my_store)

result = agent.run("save the report")
if result.status == "awaiting_approval":
    call = result.pending                 # {"call_id", "tool", "arguments", "forced"}
    # ... show it to a human, then, in this process or another one:
    result = agent.resume(result.run_id, {call["call_id"]: True})   # or False to reject

A paused run is stored as plain JSON in a StateStore. An in-memory store and a SQLite store (SQLiteStateStore(path): one local file, standard library only, not encrypted) are included, or you can write your own for Redis or a database. resume() raises ResumeError if the run is unknown, is not awaiting approval, or the decision does not match the pending call, so an approval cannot be replayed.

What was tested with a real model?

The README reports one run of 20 labeled tasks per configuration, with one model on one provider (Groq, openai/gpt-oss-20b). With the 0.3.0 wording, 19 of 20 tasks finished in JSON mode and 19 of 20 in native mode. The README itself says this is not a benchmark and recommends native mode for models that have one. It also states that the rule which blocks outgoing actions after the agent has read untrusted content has not been triggered by a real model; it is tested with scripted models only.

What this does not do

  • It is a small loop, not a platform: it has no database of its own.
  • Results from one model on one provider do not show how your model will behave. Test with yours.
  • The SQLite store is not encrypted.

RagLeap Core also has approval-gated autonomy for its AI employees, with off, semi and full modes; see the 46 roles post and the agentic patterns post.

Sources

ragleap-agents on PyPI (0.5.0), the README on GitHub, and the library page.

Back to the blog