This repository was archived by the owner on Oct 27, 2026. It is now read-only.
Repository navigation
Expand file tree
/
Copy pathtools.py
More file actions
259 lines (208 loc) · 8.6 KB
/
Copy pathtools.py
File metadata and controls
259 lines (208 loc) · 8.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
"""
Framework-Specific Tool Adapters
===============================
Convert B2A tools to framework-specific formats.
"""
from typing import Any, TypeVar
from .client import B2AClient
T = TypeVar("T")
def get_langgraph_tools(client: B2AClient) -> list[Any]:
"""
Get LangGraph-compatible tools from B2A client.
Usage:
```python
from langgraph.prebuilt import create_react_agent
from framework_integrations import B2AClient, get_langgraph_tools
client = B2AClient(api_key="...", wallet_id="...")
tools = get_langgraph_tools(client)
agent = create_react_agent(model, tools)
result = await agent.ainvoke({"messages": ["..."]})
```
Returns a list of LangChain BaseTool-compatible objects. The tools are
async (``B2AClient`` is an async client), so drive them with
``ainvoke``; LangChain refuses a sync ``invoke`` of an async-only tool
rather than returning an un-awaited coroutine.
"""
try:
from langchain_core.tools import tool
except ImportError:
raise ImportError("LangGraph not installed. Run: pip install langgraph")
@tool
async def emit_telemetry(event: str, properties: str = "{}") -> str:
"""Emit a telemetry event to track agent activity.
Args:
event: Name of the event (e.g., 'task_completed', 'error')
properties: JSON string of event properties
"""
import json
props = json.loads(properties) if properties else {}
return str(await client.emit_telemetry(event, props))
@tool
async def get_balance() -> str:
"""Get the current wallet balance in credits."""
balance = await client.get_balance()
return f"Current balance: {balance} credits"
@tool
async def send_message(
to_agent: str, content: str, priority: str = "normal"
) -> str:
"""Send a message to another agent.
Args:
to_agent: Target agent ID
content: Message content (JSON string)
priority: Message priority (normal, high, critical)
"""
import json
content_dict = json.loads(content)
return str(await client.send_message(to_agent, content_dict, priority))
@tool
async def ai_decide(context: str, options: str) -> str:
"""Make an AI-powered decision based on context.
Args:
context: JSON string with decision context
options: JSON array of option strings
"""
import json
ctx = json.loads(context)
opts = json.loads(options)
decision = await client.decide(ctx, opts)
return f"Decision: {decision}"
@tool
async def self_heal(issue: str, error_log: str = "{}") -> str:
"""AI-powered self-healing diagnostics.
Args:
issue: Description of the problem
error_log: JSON string with error context
"""
import json
ctx = json.loads(error_log)
result = await client.heal(issue, ctx)
return str(result)
@tool
async def awi_session(target_url: str, max_steps: int = 100) -> str:
"""Create an AWI session for web automation.
Args:
target_url: URL of the website to interact with
max_steps: Maximum steps for the session
"""
result = await client.create_awi_session(target_url, max_steps)
return f"Session created: {result.get('session_id', 'unknown')}"
return [
emit_telemetry,
get_balance,
send_message,
ai_decide,
self_heal,
awi_session,
]
def get_crewai_tools(client: B2AClient) -> list[Any]:
"""
Not supported: raises ``NotImplementedError``.
CrewAI executes every tool through a synchronous ``invoke`` that runs an
async tool body with ``asyncio.run`` -- a fresh event loop per call.
``B2AClient`` is an async client whose ``httpx.AsyncClient`` pools
connections on the loop that opened them, so the call after the first
fails with "Event loop is closed". The earlier sync tools never awaited
the client at all (no request was sent; the balance and AWI tools
returned a coroutine repr or crashed). Rather than hand CrewAI tools that
cannot work, this factory refuses.
Use the governed CrewAI wrapper instead (permit -> invoke -> signed
receipt): ``CrewAIB2ATool`` from ``wrappers/crewai-agent-middleware``,
or ``framework_integrations.LangGraphGovernedTools`` for LangGraph.
"""
raise NotImplementedError(
"get_crewai_tools is not supported: CrewAI runs each async tool on a "
"fresh event loop, which the async B2AClient cannot survive between "
"calls. Use the governed CrewAIB2ATool from "
"wrappers/crewai-agent-middleware, or "
"framework_integrations.LangGraphGovernedTools."
)
def get_autogen_tools(client: B2AClient) -> list[Any]:
"""
Get AutoGen-compatible tools from B2A client.
Usage:
```python
import autogen
from framework_integrations import B2AClient, get_autogen_tools
client = B2AClient(api_key="...", wallet_id="...")
tools = get_autogen_tools(client)
agent = autogen.AssistantAgent(
name="agent",
llm_config=llm_config,
function_map=tools
)
```
Returns a dict mapping function names to functions for AutoGen.
"""
return {
"emit_telemetry": client.emit_telemetry,
"get_balance": client.get_balance,
"send_message": client.send_message,
"ai_decide": client.decide,
"self_heal": client.heal,
"create_awi_session": client.create_awi_session,
}
def get_llamaindex_tools(client: B2AClient) -> list[Any]:
"""
Get LlamaIndex-compatible tools from B2A client.
Usage:
```python
from llama_index.core.agent import ReActAgent
from llama_index.core.tools import FunctionTool
from framework_integrations import B2AClient, get_llamaindex_tools
client = B2AClient(api_key="...", wallet_id="...")
tools = get_llamaindex_tools(client)
agent = ReActAgent.from_tools(tools, llm=llm)
response = await agent.achat("...")
```
Returns a list of LlamaIndex FunctionTool objects built from async
functions (``B2AClient`` is an async client), so ``acall`` awaits the
request in the caller's event loop.
"""
try:
from llama_index.core.tools import FunctionTool
except ImportError:
raise ImportError("LlamaIndex not installed. Run: pip install llama-index")
async def emit_telemetry(event: str, properties: str = "{}") -> str:
"""Emit a telemetry event to track agent activity."""
import json
props = json.loads(properties) if properties else {}
return str(await client.emit_telemetry(event, props))
async def get_balance() -> str:
"""Get the current wallet balance in credits."""
balance = await client.get_balance()
return f"Current balance: {balance} credits"
async def send_message(
to_agent: str, content: str, priority: str = "normal"
) -> str:
"""Send a message to another agent."""
import json
content_dict = json.loads(content)
return str(await client.send_message(to_agent, content_dict, priority))
async def ai_decide(context: str, options: str) -> str:
"""Make an AI-powered decision based on context."""
import json
ctx = json.loads(context)
opts = json.loads(options)
decision = await client.decide(ctx, opts)
return f"Decision: {decision}"
async def self_heal(issue: str, error_log: str = "{}") -> str:
"""AI-powered self-healing diagnostics."""
import json
ctx = json.loads(error_log)
result = await client.heal(issue, ctx)
return str(result)
async def awi_session(target_url: str, max_steps: int = 100) -> str:
"""Create an AWI session for web automation."""
result = await client.create_awi_session(target_url, max_steps)
return f"Session created: {result.get('session_id', 'unknown')}"
# async_fn, not fn: FunctionTool.acall awaits these in the caller's loop
# instead of calling a sync wrapper that hands back a coroutine.
return [
FunctionTool.from_defaults(async_fn=emit_telemetry, name="emit_telemetry"),
FunctionTool.from_defaults(async_fn=get_balance, name="get_balance"),
FunctionTool.from_defaults(async_fn=send_message, name="send_message"),
FunctionTool.from_defaults(async_fn=ai_decide, name="ai_decide"),
FunctionTool.from_defaults(async_fn=self_heal, name="self_heal"),
FunctionTool.from_defaults(async_fn=awi_session, name="awi_session"),
]