Your first decomposition
Teach the planner with a worked example via @decomposition. The decorator tags a method body with the natural-language intent it answers.
Before you start
Until now the planner had two things to go on: your primitive signatures and their docstrings. You can give it a third: worked examples. A decomposition is a method you write that composes your primitives into an answer, tagged with the natural-language query it answers. The planner never runs it; it reads it as a pattern.
1. The cart, plus a describe primitive and two examples#
The shopping cart from Track 9 gains one more primitive, describe, which turns
a cart and its total into a sentence. Then come the new part: two methods marked
with @decomposition, each composing the primitives into a worked example.
# cart.py
from opensymbolicai.core import decomposition, primitive
class ShoppingCart(PlanExecute):
# new_cart, add_item, cart_total as before ...
@primitive(read_only=True)
def describe(self, cart: Cart, total: float) -> str:
"""Describe the cart's items and what they come to, as a sentence."""
parts = [
f"{item.quantity} {name} at {item.price:g} dollars each"
for name, item in cart.items.items()
]
return f"{' and '.join(parts)} is {total:g} dollars"
@decomposition(
intent="what do 2 apples at 3 dollars each and 1 loaf of bread at 2 dollars come to?"
)
def _example_small_order(self) -> str:
cart = self.new_cart()
cart = self.add_item(cart, "apples", 3, 2)
cart = self.add_item(cart, "bread", 2, 1)
total = self.cart_total(cart)
text = self.describe(cart, total)
return text
@decomposition(intent="how much for 4 bananas at 2 dollars each?")
def _example_single_item(self) -> str:
cart = self.new_cart()
cart = self.add_item(cart, "bananas", 2, 4)
total = self.cart_total(cart)
text = self.describe(cart, total)
return textEach decomposition is ordinary Python: a method that calls your primitives
through self and returns a result. You will never call them yourself, and
neither will the planner. Their job is to be read.
The library puts both into the planner's prompt under ## Example Decompositions,
stripping self. so they read like a plan. Take the decompositions out of
cart.py and this section disappears.
2. The planner follows the pattern#
Run some orders the examples never mention, each phrased its own way:
# main.py
QUERIES = [
"ring up 5 oranges at 1 dollar each and 2 yogurts at 3 dollars each",
"what's the damage on 3 notebooks at 4 dollars each and 2 pens at 1 dollar each?",
"I'll take 10 eggs at 1 dollar each and 1 cake at 12 dollars",
]
for query in QUERIES:
result = agent.run(query)
print(result.plan)
print(result.result)uv run main.pySample output for the first query:
cart = new_cart()
cart = add_item(cart, "oranges", 1, 5)
cart = add_item(cart, "yogurts", 3, 2)
total = cart_total(cart)
text = describe(cart, total)
return text
5 oranges at 1 dollars each and 2 yogurts at 3 dollars each is 11 dollarsThe planner reused the pattern: make a cart, add items, total, describe. None of these queries matched an example word for word.
Takeaway#
@decomposition is how you show the planner how the pieces fit together. The
intent is the query the example stands for, and the body is the plan that
answers it. Write one example per distinct task shape you want the planner to
follow reliably.