pip install ragleap-tools library. For the hosted business platform, see docs.ragleap.com instead.
ragleap-tools
Standalone, dependency-light tool implementations for LLM tool-calling. Exposes OpenAI/Gemini-style function-calling schemas — ragleap-tools provides the Tool objects, not the execution loop.
Install
No configuration needed for the 12 stateless tools. File operations and document ingestion are opt-in and each need their own config object.
pip install ragleap-tools # or, with uv uv add ragleap-tools # optional, for the ragleap-rag-backed ingestion tool: pip install ragleap-tools[ingest]
What this is (and isn't)
ragleap-tools provides Tool objects — a name, a description, a JSON Schema for parameters, and a safe handler function. It does not own a tool-calling execution loop (deciding when to call a tool, running it, feeding the result back to the model) — that's ragleap-agents's job, per the roadmap's own split. Wire these tools into your own tool-calling code, or into ragleap-agents once that ships.
Quick start
from ragleap_tools import STATELESS_TOOLS, CALCULATOR_TOOL # Give these to your LLM provider's tools= parameter: openai_tools = [t.to_openai_schema() for t in STATELESS_TOOLS] gemini_tools = [t.to_gemini_schema() for t in STATELESS_TOOLS] # When the model calls one, invoke the handler yourself: result = CALCULATOR_TOOL.call(expression="2 + 2 * sqrt(16)") print(result.success, result.result) # True 10.0
Full public API
Stateless tools (v0.1.0+) — no configuration needed
CALCULATOR_TOOLeval()/exec().CURRENT_DATETIME_TOOL, ADD_TO_DATE_TOOL, DATE_DIFFERENCE_TOOLCONVERT_LENGTH_TOOL, CONVERT_WEIGHT_TOOL, CONVERT_TEMPERATURE_TOOLPARSE_JSON_TOOL, PARSE_CSV_TOOLREGEX_EXTRACT_TOOL, WORD_COUNT_TOOL, TEXT_CASE_TRANSFORM_TOOLFile operations (v0.1.0+) — sandboxed, needs configuration
from ragleap_tools import FileOpsConfig, make_file_tools config = FileOpsConfig(root_dir="/path/to/a/safe/directory") read_tool, write_tool, list_tool = make_file_tools(config)
Every operation is confined to root_dir. Paths are resolved via Path.resolve() (which follows symlinks) before containment is checked with is_relative_to() — so both ../ traversal and symlink-based escapes are rejected, not just naive string-prefix checking. There is no unsandboxed mode.
Document ingestion and search (v0.1.0+) — optional, needs ragleap-rag
from ragleap import RagLeap, ProviderConfig, EmbeddingConfig from ragleap_tools import IngestConfig, make_ingest_tool rag = RagLeap(database_url="...", primary=ProviderConfig(...), embedder=EmbeddingConfig(...)) ingest_tool = make_ingest_tool(IngestConfig(rag=rag))
Wraps ragleap-rag's already-tested ingest_text() — no new ingestion logic, just a tool schema on top of the real 28-format-capable pipeline. Same optional-dependency pattern ragleap-graph already uses for its own optional ragleap-rag link.
Version history
| Version | What shipped | Real live test performed |
|---|---|---|
| v0.1.0 | Initial release: 12 stateless tools, sandboxed file ops (FileOpsConfig, make_file_tools), optional ingestion tool (IngestConfig, make_ingest_tool) | 51 tests incl. real security tests: calculator rejects __import__/attribute access/list comprehensions/multi-statement injection; file ops blocked against a real on-disk symlink pointing outside the sandbox, not just a path-string check |
| v0.1.1 | Added search_documents (SearchConfig, make_search_tool) wrapping ragleap-rag's retrieve() for hybrid vector+keyword search, with an optional filename= to scope search to one document. Fixed ingest_document to pass metadata={"filename": filename} to ingest_text() - v0.1.0 passed no metadata at all, silently making every ingested document unfilterable by metadata_filter, which filename= depends on. | 69 tests (was 51). New: 8 tests for search_documents asserting on the fake's actually-recorded metadata_filter value, not just call-succeeded. 6 tests backfilled for ingest_document - v0.1.0 shipped it with zero direct test coverage, exactly the kind of gap that hid the metadata bug. |
Real design decisions & scope boundaries this session
Not fabricated wins — each of these was a deliberate call made before writing code, not an afterthought.
- ✓ shippedNo execution-loop ownership.
ragleap-toolsprovidesToolobjects only. The roadmap already assigns tool-calling execution + HITL approval gates toragleap-agents— avoiding two competing execution-loop implementations in the ecosystem. - ✓ shippedAST-based calculator, never eval()/exec(). Parses the expression, walks the tree, rejects anything outside an explicit allowlist of node types/functions. Verified against real code-injection payloads, not just documented as safe.
- ✓ shippedSymlink-aware file sandboxing.
Path.resolve()before containment check, not naive string-prefix matching — closes a real escape class that string-based sandboxing misses. Verified with a real on-disk symlink pointing outside the sandbox, not just a synthetic path string. - deliberately deferredCode execution, web search, HTTP fetch, and business-system connectors are explicitly out of scope for v0.1.0. Each needs its own security-focused design pass. Not rushed in alongside lower-risk tools.
Known limitations
- No tool-calling execution loop is provided — the caller (or
ragleap-agents, once it ships) must decide when to call a tool and feed results back to the model. - File ops require an explicit
root_dir— there is no unsandboxed mode, and no default directory is assumed. - Code execution, web search, HTTP fetch, and database/business-system connectors are not included in v0.1.0.