Skip to content

Commit 26314ce

Browse files
committed
updated component tool usage
Signed-off-by: Akihiko Kuroda <akihikokuroda2020@gmail.com>
1 parent ed92ca4 commit 26314ce

3 files changed

Lines changed: 48 additions & 67 deletions

File tree

docs/examples/components/README.md

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -62,14 +62,15 @@ uv run pytest docs/examples/components/duplicate_tool_names_experiments.py -v
6262
---
6363

6464
### `pattern2_context_and_tools.py`
65-
**Pattern 2 demonstration** - Shows how to combine components in context with explicit tool passing for tool calling.
65+
**Pattern 2 demonstration** - Shows how to combine components in context with automatic tool extraction for tool calling.
6666

6767
**What it shows:**
68-
- Pattern 2 approach: Components in session context + explicit tools via `ModelOption.TOOLS`
69-
- How to add context blocks and components to the session
70-
- Separating concerns: context rendering vs. tool availability
68+
- Pattern 2 approach: Components in session context with automatic tool extraction
69+
- How to add components to the session context
70+
- Backend automatically extracts tools via `add_tools_from_context_actions()` when `tool_calls=True`
7171
- Proper tool execution via Mellea's pipeline (enables telemetry)
7272
- Multi-turn stability with component ID-based prefixing
73+
- Components with templates render in the conversation
7374

7475
**Run it:**
7576
```bash
@@ -86,9 +87,10 @@ uv run python docs/examples/components/pattern2_context_and_tools.py
8687

8788
**Key concepts:**
8889
- Pattern 1: Extract tools only (simple tool calling)
89-
- Pattern 2: Components in context + explicit tools (full control)
90+
- Pattern 2: Components in context with auto-extraction (implicit tool passing)
9091
- Both patterns use component ID-based prefixing
91-
- Tools must be explicitly passed even when components are in context
92+
- NO explicit `ModelOption.TOOLS` needed - backend auto-extracts from context
93+
- Components must have valid templates for rendering
9294
- Each tool call recorded in `mellea.tool.calls` metric with component_id
9395

9496
---

docs/examples/components/duplicate_tool_names.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ def format_for_llm(self) -> TemplateRepresentation | str:
120120
obj=self,
121121
args={"description": "Database query interface"},
122122
tools={"query": MelleaTool.from_callable(self._tool.run)},
123+
template="🗄️ **Database Interface**: {{description}}\nAvailable: SQL query tool",
123124
)
124125

125126
def _parse(self, computed: ModelOutputThunk) -> str:
@@ -143,6 +144,7 @@ def format_for_llm(self) -> TemplateRepresentation | str:
143144
obj=self,
144145
args={"description": "Search interface"},
145146
tools={"query": MelleaTool.from_callable(self._tool.run)},
147+
template="🔍 **Search Interface**: {{description}}\nAvailable: Document search tool",
146148
)
147149

148150
def _parse(self, computed: ModelOutputThunk) -> str:

docs/examples/components/pattern2_context_and_tools.py

Lines changed: 38 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
from mellea.backends import ModelOption
2222
from mellea.backends.model_ids import IBM_GRANITE_4_HYBRID_MICRO
2323
from mellea.backends.openai import OpenAIBackend
24-
from mellea.backends.tools import MelleaTool, add_tools_from_context_actions
24+
from mellea.backends.tools import MelleaTool
2525
from mellea.core import CBlock, Component, ModelOutputThunk, TemplateRepresentation
2626
from mellea.core.base import AbstractMelleaTool
2727
from mellea.formatters import TemplateFormatter
@@ -116,6 +116,7 @@ def format_for_llm(self) -> TemplateRepresentation | str:
116116
obj=self,
117117
args={"description": "Database query interface"},
118118
tools={"query": MelleaTool.from_callable(self._tool.run)},
119+
template="🗄️ **Database Interface**: {{description}}\nAvailable: SQL query tool",
119120
)
120121

121122
def _parse(self, computed: ModelOutputThunk) -> str:
@@ -139,6 +140,7 @@ def format_for_llm(self) -> TemplateRepresentation | str:
139140
obj=self,
140141
args={"description": "Search interface"},
141142
tools={"query": MelleaTool.from_callable(self._tool.run)},
143+
template="🔍 **Search Interface**: {{description}}\nAvailable: Document search tool",
142144
)
143145

144146
def _parse(self, computed: ModelOutputThunk) -> str:
@@ -147,34 +149,35 @@ def _parse(self, computed: ModelOutputThunk) -> str:
147149

148150

149151
def main():
150-
"""Demonstrate Pattern 2: Components in context + explicit tools."""
152+
"""Demonstrate Pattern 2: Components in context + auto tool extraction."""
151153
print("=" * 70)
152-
print("PATTERN 2: Components in Context + Explicit Tools for Tool Calling")
154+
print("PATTERN 2: Components in Context + Auto Tool Extraction")
155+
print("=" * 70)
156+
157+
print("\n" + "=" * 70)
158+
print("STEP 1: Create Components")
153159
print("=" * 70)
154160

155161
# Create components
156162
db_component = DatabaseComponent()
157163
search_component = SearchComponent()
164+
print("✓ Created DatabaseComponent and SearchComponent with tools")
158165

159166
print("\n" + "=" * 70)
160-
print("STEP 1: Extract Tools from Components")
167+
print("STEP 2: Add Components to Context")
161168
print("=" * 70)
162169

163-
# Extract tools from components
164-
ctx_actions = [db_component, search_component]
165-
tools = {}
166-
add_tools_from_context_actions(tools, ctx_actions)
167-
168-
print("\nExtracted tools with ID-based prefixes:")
169-
for tool_name in sorted(tools.keys()):
170-
if tool_name.startswith("component_"):
171-
print(f" - {tool_name}")
172-
173-
query_tools = [k for k in tools if "query" in k]
174-
print(f"\nTotal query tools: {len(query_tools)}")
170+
# Add components to context (no templates needed - already defined!)
171+
print("\nAdding components to context...")
172+
db_component = DatabaseComponent()
173+
search_component = SearchComponent()
174+
session_ctx = ChatContext()
175+
session_ctx = session_ctx.add(db_component)
176+
session_ctx = session_ctx.add(search_component)
177+
print(" ✓ Added both components to context")
175178

176179
print("\n" + "=" * 70)
177-
print("STEP 2: Set Up Backend and Session")
180+
print("STEP 3: Set Up Backend and Session")
178181
print("=" * 70)
179182

180183
ollama_host = os.environ.get("OLLAMA_HOST", "localhost:11434")
@@ -189,32 +192,9 @@ def main():
189192
base_url=f"{ollama_host}/v1",
190193
api_key="ollama",
191194
)
192-
session = MelleaSession(backend, ctx=ChatContext())
193-
194-
print("\nSession created")
195-
196-
print("\n" + "=" * 70)
197-
print("STEP 3: Add Context for Additional Information")
198-
print("=" * 70)
199-
200-
# Add context blocks to the session (for demonstration of Pattern 2)
201-
# In a real scenario, components could be added here if they have templates
202-
print("\nAdding context information...")
203-
context_block = CBlock(
204-
"Available systems:\n"
205-
"1. Database: For querying user information\n"
206-
"2. Search: For finding documentation"
207-
)
208-
session.ctx = session.ctx.add(context_block)
209-
print(" ✓ Added context block")
195+
session = MelleaSession(backend, ctx=session_ctx)
210196

211-
# Verify items are in context
212-
context_items = session.ctx.view_for_generation()
213-
print(f"\nContext items: {len(context_items) if context_items else 0}")
214-
if context_items:
215-
for i, item in enumerate(context_items):
216-
if isinstance(item, CBlock):
217-
print(f" {i + 1}. CBlock: {item.value[:40]}...")
197+
print("\nSession created with components in context")
218198

219199
print("\n" + "=" * 70)
220200
print("STEP 4: LLM Generation with Tool Calling")
@@ -228,17 +208,16 @@ def main():
228208
)
229209

230210
print(f"\nPrompt:\n{prompt}")
231-
print(f"\nTools available: {sorted(tools.keys())}")
232211

233-
# IMPORTANT: Must explicitly pass tools via ModelOption.TOOLS
212+
# IMPORTANT: NO ModelOption.TOOLS - backend auto-extracts from context!
234213
print("\nCalling session.instruct() with:")
235-
print(f" - Components in context: {len(context_items) if context_items else 0}")
236-
print(f" - Tools via ModelOption.TOOLS: {sorted(tools.keys())}")
214+
print(" - Components in context: YES (database + search)")
215+
print(" - ModelOption.TOOLS: NO (backend auto-extracts!)")
216+
print(" - tool_calls: True")
237217

238218
response = session.instruct(
239219
prompt,
240220
model_options={
241-
ModelOption.TOOLS: tools, # ← EXPLICIT TOOLS REQUIRED
242221
ModelOption.TOOL_CHOICE: "auto",
243222
ModelOption.MAX_NEW_TOKENS: 1000,
244223
},
@@ -266,32 +245,30 @@ def main():
266245
print("Pattern 2 Summary")
267246
print("=" * 70)
268247
print("""
269-
PATTERN 2: Components in Context + Explicit Tools
248+
PATTERN 2: Components in Context + Auto Tool Extraction
270249
271250
Approach:
272-
1. Create components with tools
273-
2. Extract tools: add_tools_from_context_actions()
274-
3. Create session with ChatContext
275-
4. Add components to context: session.ctx = session.ctx.add(component)
276-
5. Pass tools explicitly: ModelOption.TOOLS = tools
277-
6. Call session.instruct() with tool_calls=True
251+
1. Create components with tools and templates
252+
2. Create session with ChatContext
253+
3. Add components to context: session.ctx = session.ctx.add(component)
254+
4. Call session.instruct() with tool_calls=True (NO ModelOption.TOOLS!)
278255
279256
Benefits:
280257
✓ Components rendered in the prompt
281-
✓ Components' tools available for tool calling
258+
✓ Components' tools automatically extracted and available
282259
✓ ID-based prefixing prevents tool collisions
283260
✓ Multi-turn stable (same instances = same IDs)
261+
✓ No explicit tool passing needed
284262
285263
Key Point:
286-
Even though components are in context, tools MUST be explicitly passed
287-
via ModelOption.TOOLS. This is intentional design - two separate concerns:
288-
- Context rendering (what the LLM sees in the conversation)
289-
- Tool availability (what tools the LLM can call)
264+
The backend automatically calls add_tools_from_context_actions() when
265+
tool_calls=True, extracting tools from all components in the context.
266+
This makes Pattern 2 truly implicit and elegant.
290267
291268
When to Use Pattern 2:
292269
- You need components to appear in the conversation
293-
- You also need their tools available for calling
294-
- You want full control over tool availability
270+
- You want their tools available for calling automatically
271+
- You prefer implicit over explicit tool passing
295272
""")
296273

297274
print("=" * 70)

0 commit comments

Comments
 (0)