Skip to main content

LLM function calling on steroids using Abstract Syntax Trees.

Project description

🌲 treelang

PyPI - Version PyPI Downloads License: MIT

Turn your toolboxes into executable Abstract Syntax Trees (ASTs) that Large Language Models can plan in a single shot. treelang lets you express arbitrarily complex workflows, keep sensitive values out of the LLM, and reuse the resulting programs as shareable, cacheable trees.

Highlights

  • One LLM call, full plan – generate an AST for a complete solution without the expensive function-call loop.
  • Complex workflows – conditionals, higher-order functions (map, filter, reduce), and nested tool invocations all live in one tree.
  • Secure + green – the LLM never sees tool results; you evaluate nodes locally while controlling cost and compliance.
  • Model Context Protocol native – ships with an MCP client provider but can work with any tool registry through the ToolProvider abstraction.
  • Composable outputs – turn ASTs into callable tools (AST.tool) or serialize/describe them for sharing, caching, or review.

What you can build

  • Enterprise copilots that must orchestrate dozens of tools with branching logic.
  • Automations that need to fan out over datasets (e.g., score/map/filter large collections asynchronously).
  • Reusable skills: persist an AST, describe it with EvalResponse.describe(), and redeploy it as a tool on your MCP server.
  • LLM evaluation loops: ask for the tree (EvalType.TREE) to inspect reasoning before execution, or walk it immediately for answers.

Quick start

Requirements

  • Python 3.12+
  • An OpenAI API key (OPENAI_API_KEY) and optional OPENAI_MODEL override (defaults to gpt-4o-2024-11-20)
  • A source of tools: an MCP server, or your own provider implementing treelang.ai.provider.ToolProvider

Install

pip install treelang

Wire up tools (MCP)

import asyncio
from contextlib import AsyncExitStack

from mcp import ClientSession
from mcp.client.streamable_http import streamable_http_client

from treelang.ai.arborist import EvalType, OpenAIArborist
from treelang.ai.provider import MCPToolProvider


async def build_arborist(stack: AsyncExitStack) -> OpenAIArborist:
    try:
        await stack.__aenter__()
        # Connect to a streamable HTTP server
        read_stream, write_stream, _ = await stack.enter_async_context(
            streamable_http_client("http://localhost:8000/mcp")
        )

        # Create a session using the client streams
        session = await stack.enter_async_context(
            ClientSession(read_stream, write_stream)
        )

        # Initialize the connection
        await session.initialize()

        # Create the Arborist
        provider = MCPToolProvider(session)
        arborist = OpenAIArborist(provider=provider, model="gpt-4o")

        return arborist

    except Exception:
        print ("Error building the Arborist")
        await stack.aclose()
        raise

Ask a question (MCP)

async def run():
    stack = AsyncExitStack()
    arborist = await build_arborist(stack)

    response = await arborist.eval(
        query="Compare next weekend flights BOS➜SFO and summarize the cheapest option.",
        type=EvalType.WALK,  # change to EvalType.TREE to inspect the JSON AST instead
    )
    print(response.content)  # fully-evaluated tool output
    if (stack):
        await stack.aclose()

if __name__ == "__main__":
    asyncio.run(run())

Use response.jsontree with AST.parse() or AST.repr() if you want to log, cache, or transform the raw tree.

Tree-first workflow

  1. GenerateOpenAIArborist assembles an AST using your available tools.
  2. Inspect – represent the tree as JSON, describe it with EvalResponse.describe(), or pretty-print it using AST.repr().
  3. EvaluateAST.eval(tree, provider) asynchronously executes every node; the LLM never sees intermediate values.
  4. Packageawait AST.tool(tree, provider) turns a tree into a callable tool so you can add it back to your MCP server.

Architecture at a glance

  • Arborist (treelang/ai/arborist.py) – orchestrates LLM calls, maintains history via the optional Memory interface, and decides whether to return ASTs or walked results.
  • Tool providers (treelang/ai/provider.py) – abstract how tools are discovered/invoked. We ship an MCP client implementation and a template for custom providers.
  • Selectors (treelang/ai/selector.py) – plug in your own tool filtering logic; AllToolsSelector ships by default.
  • Trees (treelang/trees/tree.py) – immutable node classes plus helpers such as async traversal, repr generation, and turning trees into callable tools.

Resources & examples

  • Cookbook notebooks (cookbook/) walk through building trees, call patterns, and evaluation strategies.
  • Reproducible benchmark (evaluation/eval.py) runs versioned deterministic cases without credentials, records machine-readable quality and resource metrics, and checks them against committed regression baselines. A separate manual/scheduled live workflow records comparable model quality, latency, token, and cost evidence without exposing credentials to pull requests. See evaluation/README.md for commands and baseline policy.
  • Unit tests (tests/) cover the AST core and are a good reference for expected behavior when extending nodes.

Install the locked development environment and launch the cookbook notebooks from the repository root:

uv sync --frozen --all-groups
uv run jupyter notebook cookbook/

Contributing & local development

We actively welcome contributions—see CONTRIBUTING.md for the full workflow.

Maintainers publish signed, provenance-attested releases through PyPI Trusted Publishing. See RELEASING.md for versioning, promotion, publishing, and verification instructions.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

treelang-0.10.1.tar.gz (177.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

treelang-0.10.1-py3-none-any.whl (29.1 kB view details)

Uploaded Python 3

File details

Details for the file treelang-0.10.1.tar.gz.

File metadata

  • Download URL: treelang-0.10.1.tar.gz
  • Upload date:
  • Size: 177.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for treelang-0.10.1.tar.gz
Algorithm Hash digest
SHA256 cf492e22105b984e2d8ec0486a6904a96b63fb79f992bad5cb57a4f044cfcebc
MD5 7b65c22bccd1b5cfae595aa47ac57896
BLAKE2b-256 171c0612090e1e4e90529dfacf71b5cd9521d2d5eb9701c0d45b3fb32435d380

See more details on using hashes here.

Provenance

The following attestation bundles were made for treelang-0.10.1.tar.gz:

Publisher: release.yml on cs0lar/treelang

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file treelang-0.10.1-py3-none-any.whl.

File metadata

  • Download URL: treelang-0.10.1-py3-none-any.whl
  • Upload date:
  • Size: 29.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for treelang-0.10.1-py3-none-any.whl
Algorithm Hash digest
SHA256 47dd3f488d638901564cb35fe4d1286f59c07dc5bd0b9afcbb29390b7eb43c08
MD5 954568acce51720aaa89ab77a788c37b
BLAKE2b-256 1f51e02d533e5a2f243861bad861972587dc496904a5fe35aa51bd788fbabfd8

See more details on using hashes here.

Provenance

The following attestation bundles were made for treelang-0.10.1-py3-none-any.whl:

Publisher: release.yml on cs0lar/treelang

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page