Wrap existing code¶
Use registry.wrap() for code you cannot or will not edit. The code stays as it is.
All options go at the call site.
1. The existing code¶
# Existing code. None of it changes.
def get_articles(article_list: list[str], lang: str, debug: bool = False) -> dict[str, str]:
"""Return the text of help-center articles.
Args:
article_list: Article topics, e.g. ["returns", "shipping"].
lang: Language code.
debug: Verbose output.
"""
return {article: f"Article {article} ({lang})" for article in article_list}
class RateService:
"""Shipping rates for one region."""
def __init__(self, region: str) -> None:
self.region = region
def lookup(self, item: str) -> float:
"""Return the shipping rate for an item, in percent of the order value.
Args:
item: Item name.
"""
return 18.0 if self.region == "us" else 5.0
def convert(amount: float, rate: float) -> float:
"""Convert a USD amount with an exchange rate.
Args:
amount: Amount in USD.
rate: Units of the target currency per USD.
"""
return round(amount * rate, 2)
2. Wrap it¶
registry.wrap(
get_articles,
description="Full text of help-center articles.",
fixed={"lang": "en"}, # bound value; the LLM never sees it
hide="debug", # hidden; its default applies
rename={"article_list": "articles"}, # the LLM sees `articles`
result=lambda texts: list(texts.values()), # adapt the return shape
parallel_safe=True,
)
# A bound method: register obj.method, not the method in the class body.
registry.wrap(RateService("us").lookup, name="shipping_rate")
# A partial: its keyword bindings act like fixed= values.
registry.wrap(functools.partial(convert, rate=0.79), name="usd_to_gbp")
# One function, several tools with different fixed values.
registry.wrap(convert, name="usd_to_eur", fixed={"rate": 0.92})
flowchart LR
subgraph PY["Python signature"]
p1["article_list: list[str]"]
p2["lang: str"]
p3["debug: bool = False"]
end
subgraph LLM["What the LLM sees"]
s1["articles: array of string"]
end
p1 -- "rename=" --> s1
p2 -. "fixed= (en)" .-> H["hidden"]
p3 -. "hide=" .-> H
| Option | Effect | Rule |
|---|---|---|
fixed={"lang": "en"} |
bound value, hidden from the LLM | the name must be a parameter |
hide="debug" (or a list) |
hidden; the default applies | needs a plain default, not Field() |
rename={"article_list": "articles"} |
the LLM sees articles |
cannot rename a fixed or hidden parameter |
result=fn |
transforms the return value | turns off result_schema() |
name=, description= |
override the function name and docstring | name matches [A-Za-z_][A-Za-z0-9_]*, max 64 |
| policy options | kind, tags, parallel_safe, ... |
type-checked at build time; enforced by the executor |
3. Call it¶
spec = registry.get("get_articles")
print(list(spec.json_schema()["properties"])) # ['articles']
print(dict(spec.llm_to_python)) # {'articles': 'article_list'}
executor = Executor(registry) # every call goes through the executor's policies
articles = await executor.run("get_articles", {"articles": ["returns"]})
print(articles) # ['Article returns (en)']
print(await executor.run("shipping_rate", {"item": "laptop"})) # 18.0
print(await executor.run("usd_to_gbp", {"amount": 10})) # 7.9
print(await executor.run("usd_to_eur", {"amount": 10})) # 9.2
The model sends articles. The function receives article_list, plus lang="en" and
debug=False. spec.llm_to_python holds the reverse map. Run every call through the
executor, as here: spec.invoke skips approval, budgets and guards, so keep it for tests.
Methods, classes and blocking code¶
Register the bound method: registry.wrap(RateService("us").lookup). A whole legacy
class, its blocking sync calls and its own exceptions are on
Wrap a legacy class.
Partials¶
A functools.partial takes its name and docstring from the wrapped function. Its
keyword bindings act like fixed=: hidden and never overridable.
- Passing
fixed=for a name the partial already binds raisesToolDefinitionError. - A partial must not bind the
ToolContextparameter. The context is injected at call time.
Callable objects¶
An object with __call__ works too. It has no __name__, so pass name=. Its
description comes from the class or __call__ docstring.
This page's code is examples/wrap_existing.py. The test suite runs it.