Skip to content

Commit b82e846

Browse files
committed
fixed up plugins
1 parent ec40e9d commit b82e846

30 files changed

+1580
-772
lines changed

examples/demo_all_parser_plugins.py

Lines changed: 0 additions & 125 deletions
This file was deleted.

examples/demo_langchain_tool.py

Lines changed: 53 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,83 @@
1+
#!/usr/bin/env python
12
# examples/demo_langchain_tool.py
23
"""
3-
Demo: register a LangChain `BaseTool` with chuk-tool-processor and invoke it.
4+
Demo: expose a LangChain `BaseTool` as an async-native chuk-tool.
45
"""
56

67
from __future__ import annotations
78
import asyncio
8-
from typing import ClassVar, Any
9+
from typing import Any, ClassVar
910

1011
from langchain.tools.base import BaseTool
11-
from chuk_tool_processor.registry.auto_register import register_langchain_tool
12-
from chuk_tool_processor.core.processor import ToolProcessor
12+
13+
from chuk_tool_processor.registry import initialize, register_tool
14+
from chuk_tool_processor.execution.tool_executor import ToolExecutor
1315
from chuk_tool_processor.models.tool_call import ToolCall
1416

1517

16-
# ── LangChain tool definition ───────────────────────────────────────────────
18+
# ----------------------------------------------------------------------
19+
# 1. A regular LangChain tool (sync + async implementations)
20+
# ----------------------------------------------------------------------
1721
class PalindromeTool(BaseTool):
18-
# pydantic requires concrete type annotations here
1922
name: ClassVar[str] = "palindrome_tool"
20-
description: ClassVar[str] = (
21-
"Return whether the given text is a palindrome."
22-
)
23+
description: ClassVar[str] = "Return whether the given text is a palindrome."
2324

24-
# synchronous implementation (BaseTool will call this from .run/.arun)
25+
# sync entry-point used by BaseTool.run()
2526
def _run(self, tool_input: str, *args: Any, **kwargs: Any) -> dict:
2627
is_pal = tool_input.lower() == tool_input[::-1].lower()
2728
return {"text": tool_input, "palindrome": is_pal}
2829

29-
# asynchronous implementation (optional but nice to have)
30-
async def _arun(
31-
self, tool_input: str, run_manager: Any | None = None, **kwargs: Any
32-
) -> dict: # noqa: D401
33-
# Just delegate to the sync version for this demo
30+
# async entry-point used by BaseTool.arun()
31+
async def _arun( # noqa: D401
32+
self,
33+
tool_input: str,
34+
run_manager: Any | None = None,
35+
**kwargs: Any,
36+
) -> dict:
3437
return self._run(tool_input)
3538

3639

37-
# ── register with the global registry ───────────────────────────────────────
38-
register_langchain_tool(PalindromeTool())
40+
# ----------------------------------------------------------------------
41+
# 2. Minimal async wrapper exposing `.execute()` for the executor
42+
# ----------------------------------------------------------------------
43+
@register_tool(name="palindrome_tool")
44+
class PalindromeAdapter:
45+
"""
46+
Thin adapter that forwards the call to the LangChain tool’s
47+
async API and simply returns its result.
48+
"""
49+
50+
def __init__(self) -> None:
51+
# One tool instance is enough; LangChain tools are thread-safe.
52+
self._tool = PalindromeTool()
53+
54+
async def execute(self, tool_input: str) -> dict: # chuk-tool signature
55+
return await self._tool.arun(tool_input=tool_input)
3956

4057

41-
# ── quick test run ──────────────────────────────────────────────────────────
58+
# ----------------------------------------------------------------------
59+
# 3. Demo run
60+
# ----------------------------------------------------------------------
4261
async def main() -> None:
43-
proc = ToolProcessor(enable_caching=False)
62+
# Initialise the default registry *and* make sure our adapter is loaded
63+
registry = await initialize() # returns the same singleton each call
4464

45-
# Pretend the LLM called the tool with {"tool_input": "Madam"}
65+
# Create an executor bound to that registry
66+
executor = ToolExecutor(registry=registry)
67+
68+
# Simulate an LLM-produced tool-call
4669
call = ToolCall(tool="palindrome_tool", arguments={"tool_input": "Madam"})
47-
[result] = await proc.executor.execute([call])
4870

49-
print("Tool results:")
50-
print("·", result.tool, result.result)
71+
# Execute
72+
(result,) = await executor.execute([call])
73+
74+
# Show the outcome
75+
print("\n=== LangChain Tool Demo ===")
76+
if result.error:
77+
print("ERROR:", result.error)
78+
else:
79+
print("Tool :", result.tool)
80+
print("Data :", result.result)
5181

5282

5383
if __name__ == "__main__":
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
# examples/execution_strategies_custom_demo.py
2+
#!/usr/bin/env python
3+
"""
4+
Example: a *toy* execution strategy that just upper-cases the tool name
5+
and returns immediately - no real work, but shows the plumbing.
6+
"""
7+
8+
import asyncio
9+
import random
10+
from typing import List, Optional
11+
12+
from chuk_tool_processor.models.execution_strategy import ExecutionStrategy
13+
from chuk_tool_processor.models.tool_call import ToolCall
14+
from chuk_tool_processor.models.tool_result import ToolResult
15+
from chuk_tool_processor.plugins.discovery import plugin_registry
16+
from chuk_tool_processor.execution.tool_executor import ToolExecutor
17+
from chuk_tool_processor.registry import initialize # default in-memory registry
18+
19+
20+
# ---------------------------------------------------------------------
21+
# Strategy definition
22+
# ---------------------------------------------------------------------
23+
class ShoutStrategy(ExecutionStrategy):
24+
"""Returns the tool-name capitalised after a small random delay."""
25+
26+
async def run(
27+
self,
28+
calls: List[ToolCall],
29+
timeout: Optional[float] = None,
30+
) -> List[ToolResult]:
31+
async def _one(call: ToolCall) -> ToolResult:
32+
await asyncio.sleep(random.uniform(0.05, 0.2))
33+
return ToolResult(tool=call.tool, result=call.tool.upper())
34+
35+
return await asyncio.gather(*(_one(c) for c in calls))
36+
37+
# opt-in streaming
38+
@property
39+
def supports_streaming(self) -> bool:
40+
return True
41+
42+
async def stream_run(self, calls, timeout=None):
43+
for c in calls:
44+
yield ToolResult(tool=c.tool, result=c.tool.upper())
45+
await asyncio.sleep(0.05)
46+
47+
48+
# Register it so discovery can find it later
49+
plugin_registry.register_plugin("execution_strategy", "ShoutStrategy", ShoutStrategy)
50+
51+
52+
# ---------------------------------------------------------------------
53+
# Try it out
54+
# ---------------------------------------------------------------------
55+
async def main() -> None:
56+
registry = await initialize() # we don’t need real tools for this demo
57+
calls = [ToolCall(tool="ping"), ToolCall(tool="echo")]
58+
executor = ToolExecutor(registry=registry, strategy=ShoutStrategy())
59+
60+
res = await executor.execute(calls)
61+
print("=== run() → list ===")
62+
for r in res:
63+
print(r)
64+
65+
print("\n=== stream_execute() ===")
66+
async for r in executor.stream_execute(calls):
67+
print(r)
68+
69+
70+
if __name__ == "__main__":
71+
asyncio.run(main())

examples/mcp_stdio_example_calling_usage.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,9 @@
2424
from chuk_tool_processor.mcp import setup_mcp_stdio
2525
from chuk_tool_processor.registry import ToolRegistryProvider
2626

27-
from chuk_tool_processor.plugins.parsers.json_tool_plugin import JsonToolPlugin
27+
from chuk_tool_processor.plugins.parsers.json_tool import JsonToolPlugin
2828
from chuk_tool_processor.plugins.parsers.xml_tool import XmlToolPlugin
29-
from chuk_tool_processor.plugins.parsers.function_call_tool_plugin import FunctionCallPlugin
29+
from chuk_tool_processor.plugins.parsers.function_call_tool import FunctionCallPlugin
3030
from chuk_tool_processor.models.tool_call import ToolCall
3131
from chuk_tool_processor.models.tool_result import ToolResult
3232

0 commit comments

Comments
 (0)