clap-agents 0.3.0__py3-none-any.whl → 0.3.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
clap/__init__.py CHANGED
@@ -12,7 +12,7 @@ from .embedding.base_embedding import EmbeddingFunctionInterface
12
12
 
13
13
  from .vector_stores.base import VectorStoreInterface, QueryResult
14
14
 
15
- from .mcp_client.client import MCPClientManager, SseServerConfig
15
+ from .mcp_client.client import MCPClientManager, ServerConfig, TransportType
16
16
 
17
17
  from .tools.web_search import duckduckgo_search
18
18
 
@@ -57,7 +57,7 @@ class FastEmbedEmbeddings(EmbeddingFunctionInterface):
57
57
  except Exception as e:
58
58
  raise RuntimeError(f"Failed to initialize fastembed model '{self.model_name}': {e}")
59
59
 
60
- async def __call__(self, input: List[str]) -> List[List[float]]: # Changed to 'input'
60
+ async def __call__(self, input: List[str]) -> List[List[float]]:
61
61
  if not input: return []
62
62
  if not _FASTEMBED_LIB_AVAILABLE: raise RuntimeError("FastEmbed library not available.")
63
63
 
@@ -1,4 +1,3 @@
1
- # src/clap/llm_services/__init__.py
2
1
  from .base import LLMServiceInterface, StandardizedLLMResponse, LLMToolCall
3
2
  from .groq_service import GroqService
4
3
  from .google_openai_compat_service import GoogleOpenAICompatService
clap/llm_services/base.py CHANGED
@@ -32,7 +32,6 @@ class LLMServiceInterface(abc.ABC):
32
32
  messages: List[Dict[str, Any]],
33
33
  tools: Optional[List[Dict[str, Any]]] = None,
34
34
  tool_choice: str = "auto",
35
- # Optional:
36
35
  # temperature: Optional[float] = None,
37
36
  # max_tokens: Optional[int] = None,
38
37
  ) -> StandardizedLLMResponse:
@@ -64,27 +64,35 @@ class OllamaOpenAICompatService(LLMServiceInterface):
64
64
  if not request_model: raise ValueError("Ollama model name not specified.")
65
65
  try:
66
66
  api_kwargs: Dict[str, Any] = {"messages": messages, "model": request_model}
67
+
67
68
  if tools and tool_choice != "none":
68
69
  api_kwargs["tools"] = tools
69
70
  if isinstance(tool_choice, dict) or tool_choice in ["auto", "required", "none"]: api_kwargs["tool_choice"] = tool_choice
70
71
  else: api_kwargs["tools"] = None; api_kwargs["tool_choice"] = None
72
+
71
73
  if temperature is not None: api_kwargs["temperature"] = temperature
72
74
  if max_tokens is not None: api_kwargs["max_tokens"] = max_tokens
73
75
  api_kwargs = {k: v for k, v in api_kwargs.items() if v is not None}
74
76
  # print(f"OllamaService: Sending request to model '{request_model}'")
75
77
  response = await self._client.chat.completions.create(**api_kwargs)
78
+
76
79
  message = response.choices[0].message
80
+
77
81
  text_content = message.content
78
82
  tool_calls_std: List[LLMToolCall] = []
83
+
79
84
  if message.tool_calls:
80
85
  for tc in message.tool_calls:
81
86
  if tc.id and tc.function and tc.function.name and tc.function.arguments is not None:
82
87
  tool_calls_std.append(LLMToolCall(id=tc.id, function_name=tc.function.name, function_arguments_json_str=tc.function.arguments))
83
88
  else: print(f"{Fore.YELLOW}Warning: Incomplete tool_call from Ollama: {tc}{Fore.RESET}")
89
+
84
90
  return StandardizedLLMResponse(text_content=text_content, tool_calls=tool_calls_std)
91
+
85
92
  except _OpenAIError_Placeholder_Type as e: # Use placeholder
86
93
  err_msg = f"Ollama (OpenAI Compat) API Error: {e}"
87
94
  if hasattr(e, 'response') and e.response and hasattr(e.response, 'text'): err_msg += f" - Details: {e.response.text}"
95
+
88
96
  print(f"{Fore.RED}{err_msg}{Fore.RESET}")
89
97
  return StandardizedLLMResponse(text_content=err_msg)
90
98
  except Exception as e:
clap/mcp_client/client.py CHANGED
@@ -1,35 +1,69 @@
1
-
2
1
  import asyncio
3
2
  import json
4
3
  from contextlib import AsyncExitStack
5
4
  from typing import Any, Dict, List, Optional
5
+ from enum import Enum
6
6
 
7
- from pydantic import BaseModel, Field, HttpUrl
7
+ from pydantic import BaseModel, Field, HttpUrl , model_validator
8
+ from colorama import Fore
8
9
 
9
10
  from mcp import ClientSession, types
10
11
  from mcp.client.sse import sse_client
11
- from colorama import Fore
12
-
13
- class SseServerConfig(BaseModel):
14
- """Configuration for connecting to an MCP server via SSE."""
15
- url: HttpUrl = Field(description="The base URL of the MCP SSE server.")
12
+ from mcp.client.streamable_http import streamablehttp_client
13
+ from mcp.client.stdio import stdio_client, StdioServerParameters
14
+
15
+
16
+ # Define an Enum for transport types for clarity and type safety
17
+ class TransportType(str, Enum):
18
+ STREAMABLE_HTTP = "streamable_http"
19
+ SSE = "sse"
20
+ STDIO = 'stdio'
21
+
22
+ # Rename SseServerConfig to ServerConfig and add the transport field
23
+ class ServerConfig(BaseModel):
24
+ """Configuration for connecting to an MCP server."""
25
+ transport: TransportType = Field(
26
+ default=TransportType.STREAMABLE_HTTP,
27
+ description="The MCP transport to use."
28
+ )
29
+ # Fields for HTTP-based transports
30
+ url: Optional[HttpUrl] = Field(default=None, description="The base URL for HTTP/SSE based MCP servers.")
16
31
  headers: Optional[Dict[str, str]] = Field(default=None, description="Optional headers for the connection.")
32
+
33
+ # Fields for STDIO transport
34
+ command: Optional[str] = Field(default=None, description="The command to execute for stdio-based servers.")
35
+ args: Optional[List[str]] = Field(default=None, description="A list of arguments for the command.")
36
+
37
+ @model_validator(mode='after')
38
+ def check_transport_params(self) -> 'ServerConfig':
39
+ """Ensures the correct parameters are provided for the chosen transport."""
40
+ if self.transport in [TransportType.STREAMABLE_HTTP, TransportType.SSE]:
41
+ if not self.url:
42
+ raise ValueError(f"'url' is required for '{self.transport.value}' transport")
43
+ elif self.transport == TransportType.STDIO:
44
+ if not self.command:
45
+ raise ValueError(f"'command' is required for '{self.transport.value}' transport")
46
+
47
+ return self
17
48
 
49
+ # Update the class docstring to be more generic
18
50
  class MCPClientManager:
19
51
  """
20
- Manages connections and interactions with multiple MCP servers via SSE.
52
+ Manages connections and interactions with multiple MCP servers via supported
53
+ MCP transports (Streamable HTTP, SSE).
21
54
 
22
55
  Handles connecting, disconnecting, listing tools, and calling tools on
23
56
  configured MCP servers accessible over HTTP/S.
24
57
  """
25
58
 
26
- def __init__(self, server_configs: Dict[str, SseServerConfig]):
59
+ # Update the __init__ method to use the new ServerConfig
60
+ def __init__(self, server_configs: Dict[str, ServerConfig]):
27
61
  """
28
- Initializes the manager with SSE server configurations.
62
+ Initializes the manager with server configurations.
29
63
 
30
64
  Args:
31
65
  server_configs: A dictionary where keys are logical server names
32
- and values are SseServerConfig objects.
66
+ and values are ServerConfig objects.
33
67
  """
34
68
  if not isinstance(server_configs, dict):
35
69
  raise TypeError("server_configs must be a dictionary.")
@@ -39,11 +73,11 @@ class MCPClientManager:
39
73
  self._connect_locks: Dict[str, asyncio.Lock] = {
40
74
  name: asyncio.Lock() for name in server_configs
41
75
  }
42
- self._manager_lock = asyncio.Lock() # General lock for manager state
76
+ self._manager_lock = asyncio.Lock()
43
77
 
44
78
  async def _ensure_connected(self, server_name: str):
45
79
  """
46
- Ensures a connection via SSE to the specified server is active.
80
+ Ensures a connection to the specified server is active using the configured transport.
47
81
 
48
82
  Args:
49
83
  server_name: The logical name of the server to connect to.
@@ -67,43 +101,68 @@ class MCPClientManager:
67
101
  if not config:
68
102
  raise ValueError(f"Configuration for server '{server_name}' not found.")
69
103
 
70
- print(f"{Fore.YELLOW}Attempting to connect to MCP server via SSE: {server_name} at {config.url}{Fore.RESET}")
71
-
72
- # Construct the specific SSE endpoint URL (often /sse)
73
- sse_url = str(config.url).rstrip('/') + "/sse"
74
-
75
104
  exit_stack = AsyncExitStack()
76
105
  try:
77
-
78
- sse_transport = await exit_stack.enter_async_context(
79
- sse_client(url=sse_url, headers=config.headers)
80
- )
81
- read_stream, write_stream = sse_transport
106
+ if config.transport == TransportType.STDIO:
107
+ if not config.command:
108
+ raise ValueError("Cannot connect to STDIO server without a 'command'.")
109
+
110
+ print(f"{Fore.YELLOW}Attempting to connect to MCP server '{server_name}' using STDIO transport...{Fore.RESET}")
111
+ print(f" Command: {config.command} {' '.join(config.args or [])}")
112
+
113
+ server_params = StdioServerParameters(command=config.command, args=config.args or [])
114
+ stdio_transport_streams = await exit_stack.enter_async_context(
115
+ stdio_client(server_params)
116
+ )
117
+ read_stream, write_stream = stdio_transport_streams
118
+ transport_name = "STDIO"
119
+ # Core logic change - branch based on the configured transport
120
+ elif config.transport == TransportType.STREAMABLE_HTTP:
121
+ mcp_endpoint_url = str(config.url).rstrip('/')
122
+ print(f"{Fore.YELLOW}Attempting to connect to MCP server '{server_name}' at {mcp_endpoint_url} using Streamable HTTP transport...{Fore.RESET}")
123
+
124
+ # Use the new streamablehttp_client
125
+ http_transport = await exit_stack.enter_async_context(
126
+ streamablehttp_client(url=mcp_endpoint_url, headers=config.headers, auth=None)
127
+ )
128
+ # It returns three values; we only need the first two.
129
+ read_stream, write_stream, _ = http_transport
130
+ transport_name = "Streamable HTTP"
131
+
132
+ elif config.transport == TransportType.SSE:
133
+ # This branch maintains backward compatibility
134
+ sse_url = str(config.url).rstrip('/') + "/sse"
135
+ print(f"{Fore.YELLOW}Attempting to connect to MCP server '{server_name}' at {sse_url} using legacy SSE transport...{Fore.RESET}")
136
+
137
+ # Use the old sse_client
138
+ sse_transport = await exit_stack.enter_async_context(
139
+ sse_client(url=sse_url, headers=config.headers)
140
+ )
141
+ read_stream, write_stream = sse_transport
142
+ transport_name = "legacy SSE"
143
+
144
+ else:
145
+ raise ValueError(f"Unsupported transport type configured for server '{server_name}': {config.transport}")
82
146
 
83
-
84
147
  session = await exit_stack.enter_async_context(
85
148
  ClientSession(read_stream, write_stream)
86
149
  )
87
150
 
88
-
89
151
  await session.initialize()
90
152
 
91
153
  async with self._manager_lock:
92
154
  self.sessions[server_name] = session
93
155
  self.exit_stacks[server_name] = exit_stack
94
- print(f"{Fore.GREEN}Successfully connected to MCP server via SSE: {server_name}{Fore.RESET}")
156
+ print(f"{Fore.GREEN}Successfully connected to MCP server '{server_name}' via {transport_name}{Fore.RESET}")
95
157
 
96
158
  except Exception as e:
97
159
  await exit_stack.aclose()
98
- print(f"{Fore.RED}Failed to connect to MCP server '{server_name}' via SSE: {e}{Fore.RESET}")
99
- raise RuntimeError(f"SSE connection to '{server_name}' failed.") from e
160
+ print(f"{Fore.RED}Failed to connect to MCP server '{server_name}': {e}{Fore.RESET}")
161
+ raise RuntimeError(f"Connection to '{server_name}' failed.") from e
100
162
 
101
163
  async def disconnect(self, server_name: str):
102
164
  """
103
165
  Disconnects from a specific server and cleans up resources.
104
-
105
- Args:
106
- server_name: The logical name of the server to disconnect from.
107
166
  """
108
167
  async with self._manager_lock:
109
168
  if server_name in self.sessions:
@@ -113,7 +172,7 @@ class MCPClientManager:
113
172
  await exit_stack.aclose()
114
173
  print(f"{Fore.GREEN}Disconnected from MCP server: {server_name}{Fore.RESET}")
115
174
 
116
-
175
+
117
176
  async def disconnect_all(self):
118
177
  server_names = list(self.sessions.keys())
119
178
  print(f"{Fore.YELLOW}MCPClientManager: Disconnecting from all servers ({len(server_names)})...{Fore.RESET}")
@@ -126,13 +185,7 @@ class MCPClientManager:
126
185
 
127
186
  async def list_remote_tools(self, server_name: str) -> List[types.Tool]:
128
187
  """
129
- Lists tools available on a specific connected SSE server.
130
-
131
- Args:
132
- server_name: The logical name of the server.
133
-
134
- Returns:
135
- A list of mcp.types.Tool objects provided by the server.
188
+ Lists tools available on a specific connected server.
136
189
  """
137
190
  await self._ensure_connected(server_name)
138
191
  session = self.sessions.get(server_name)
@@ -152,15 +205,7 @@ class MCPClientManager:
152
205
  self, server_name: str, tool_name: str, arguments: Dict[str, Any]
153
206
  ) -> str:
154
207
  """
155
- Calls a tool on a specific connected SSE server.
156
-
157
- Args:
158
- server_name: The logical name of the server.
159
- tool_name: The name of the tool to call.
160
- arguments: A dictionary of arguments for the tool.
161
-
162
- Returns:
163
- A string representation of the tool's result content.
208
+ Calls a tool on a specific connected server.
164
209
  """
165
210
  await self._ensure_connected(server_name)
166
211
  session = self.sessions.get(server_name)
@@ -193,4 +238,4 @@ class MCPClientManager:
193
238
 
194
239
  except Exception as e:
195
240
  print(f"{Fore.RED}Error calling tool '{tool_name}' on server '{server_name}': {e}{Fore.RESET}")
196
- raise RuntimeError(f"Failed to call tool '{tool_name}' on '{server_name}'.") from e
241
+ raise RuntimeError(f"Failed to call tool '{tool_name}' on '{server_name}'.") from e
@@ -74,6 +74,7 @@ class Agent:
74
74
  mcp_server_names: Optional[List[str]] = None,
75
75
  vector_store: Optional[VectorStoreInterface] = None,
76
76
  parallel_tool_calls: bool = True ,
77
+ **kwargs
77
78
  # embedding_function: Optional[EmbeddingFunction] = None,
78
79
 
79
80
  ):
@@ -86,6 +87,7 @@ class Agent:
86
87
  self.local_tools = tools or []
87
88
 
88
89
  self.vector_store = vector_store
90
+ self.react_agent_kwargs = kwargs
89
91
  # self.embedding_function = embedding_function
90
92
 
91
93
  llm_service_instance = llm_service or GroqService()
@@ -193,7 +195,7 @@ class Agent:
193
195
  self.task_description = original_task_description
194
196
 
195
197
  print(f"Agent {self.name}: Running ReactAgent...")
196
- raw_output = await self.react_agent.run(user_msg=msg)
198
+ raw_output = await self.react_agent.run(user_msg=msg,**self.react_agent_kwargs)
197
199
  output_data = {"output": raw_output}
198
200
 
199
201
  print(f"Agent {self.name}: Passing context to {len(self.dependents)} dependents...")
clap/tool_pattern/tool.py CHANGED
@@ -16,9 +16,11 @@ def get_fn_signature(fn: Callable) -> dict:
16
16
  sig = inspect.signature(fn)
17
17
  for name, type_hint in fn.__annotations__.items():
18
18
  if name == "return": continue
19
+
19
20
  param_type_name = getattr(type_hint, "__name__", str(type_hint))
20
21
  schema_type = type_mapping.get(param_type_name.lower(), "string")
21
22
  parameters["properties"][name] = {"type": schema_type}
23
+
22
24
  if sig.parameters[name].default is inspect.Parameter.empty:
23
25
  parameters["required"].append(name)
24
26
  if not parameters.get("required"):
clap/tools/web3_tools.py CHANGED
@@ -3,18 +3,15 @@ from web3 import Web3
3
3
  from clap.tool_pattern.tool import tool
4
4
  import json
5
5
 
6
- # Environment variables are loaded by the main application script.
7
6
 
8
7
  WEB3_PROVIDER_URL = os.getenv("WEB3_PROVIDER_URL")
9
8
  AGENT_PRIVATE_KEY = os.getenv("AGENT_PRIVATE_KEY")
10
9
 
11
- # --- Official Testnet Addresses ---
12
10
  WETH_CONTRACT_ADDRESS = "0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14"
13
11
  UNISWAP_ROUTER_ADDRESS = "0x3bFA4769FB09eefC5a399D6D47036A5d3fA67B54"
14
12
  CHAINLINK_ETH_USD_PRICE_FEED_ADDRESS = "0x694AA1769357215DE4FAC081bf1f309aDC325306"
15
13
 
16
14
 
17
- # --- Correct, Centralized ABIs ---
18
15
  CHAINLINK_PRICE_FEED_ABI = """
19
16
  [
20
17
  {
@@ -106,14 +103,11 @@ def get_token_price(token_pair: str) -> str:
106
103
  abi=CHAINLINK_PRICE_FEED_ABI
107
104
  )
108
105
 
109
- # The latestRoundData function returns a tuple of values. The price is the second element.
110
106
  latest_data = price_feed_contract.functions.latestRoundData().call()
111
107
  price_raw = latest_data[1]
112
108
 
113
- # The price feed also has a 'decimals' function to tell us where to put the decimal point.
114
109
  price_decimals = price_feed_contract.functions.decimals().call()
115
110
 
116
- # Convert the raw price to a human-readable format
117
111
  price = price_raw / (10 ** price_decimals)
118
112
 
119
113
  return f"The latest price for {token_pair} is ${price:.2f}"
@@ -174,7 +168,6 @@ def interact_with_contract(
174
168
  try:
175
169
  _initialize_web3()
176
170
 
177
- # 1. Validate inputs
178
171
  if not w3.is_address(contract_address):
179
172
  return "Error: Invalid 'contract_address'."
180
173
  try:
@@ -182,20 +175,17 @@ def interact_with_contract(
182
175
  except json.JSONDecodeError:
183
176
  return "Error: The provided 'abi' is not a valid JSON string."
184
177
 
185
- # 2. Create the contract object
186
178
  contract = w3.eth.contract(address=contract_address, abi=abi_json)
187
179
 
188
- # 3. Get the function object from the contract
189
180
  func_to_call = getattr(contract.functions, function_name)
190
181
  if not func_to_call:
191
182
  return f"Error: Function '{function_name}' not found in the contract's ABI."
192
183
 
193
- # 4. Prepare the function call with its arguments
194
184
  prepared_func = func_to_call(*function_args)
195
185
 
196
- # 5. Execute as either a read-only 'call' or a write 'transaction'
186
+
197
187
  if is_write_transaction:
198
- # This is a state-changing transaction that costs gas
188
+
199
189
  nonce = w3.eth.get_transaction_count(agent_account.address)
200
190
  tx = prepared_func.build_transaction({
201
191
  'from': agent_account.address,
@@ -206,9 +196,9 @@ def interact_with_contract(
206
196
  tx_hash = w3.eth.send_raw_transaction(signed_tx.raw_transaction)
207
197
  return f"Write transaction sent successfully. Transaction hash: {w3.to_hex(tx_hash)}"
208
198
  else:
209
- # This is a read-only call that is free and instant
199
+
210
200
  result = prepared_func.call()
211
- # Convert the result to a JSON string to ensure it's readable by the LLM
201
+
212
202
  return json.dumps(result)
213
203
 
214
204
  except Exception as e:
@@ -224,7 +214,7 @@ def get_erc20_balance(token_address: str, wallet_address: str) -> str:
224
214
 
225
215
  token_contract = w3.eth.contract(address=chk_token_address, abi=ERC20_STANDARD_ABI)
226
216
 
227
- # This will now work correctly with a real contract address
217
+
228
218
  decimals = token_contract.functions.decimals().call()
229
219
  raw_balance = token_contract.functions.balanceOf(chk_wallet_address).call()
230
220
 
@@ -232,7 +222,7 @@ def get_erc20_balance(token_address: str, wallet_address: str) -> str:
232
222
  return str(balance)
233
223
 
234
224
  except Exception as e:
235
- # A simple, honest error handler for genuine problems.
225
+
236
226
  return f"Error in get_erc20_balance for token {token_address}: {e}"
237
227
 
238
228
  @tool
@@ -278,12 +268,11 @@ def swap_tokens_for_tokens(token_in_address: str, token_out_address: str, amount
278
268
  signed_approve_tx = w3.eth.account.sign_transaction(approve_tx, private_key=os.getenv("AGENT_PRIVATE_KEY"))
279
269
  approve_tx_hash = w3.eth.send_raw_transaction(signed_approve_tx.raw_transaction)
280
270
 
281
- # --- THE FIX ---
282
- # Wait for the approval transaction to be confirmed.
271
+
283
272
  print(f"Waiting for approval transaction {w3.to_hex(approve_tx_hash)} to be confirmed...")
284
273
  w3.eth.wait_for_transaction_receipt(approve_tx_hash)
285
274
 
286
- # Step 2: Swap
275
+
287
276
  uniswap_router = w3.eth.contract(address=chk_router_address, abi=UNISWAP_ABI)
288
277
  swap_params = (chk_token_in, chk_token_out, fee, agent_account.address, amount_in_wei, 0, 0)
289
278
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: clap-agents
3
- Version: 0.3.0
3
+ Version: 0.3.2
4
4
  Summary: A Python framework for building cognitive agentic patterns including ReAct agents, Multi-Agent Teams, native tool calling, and MCP client integration.
5
5
  Project-URL: Homepage, https://github.com/MaitreyaM/CLAP-AGENTS.git
6
6
  Project-URL: Repository, https://github.com/MaitreyaM/CLAP-AGENTS.git
@@ -513,24 +513,26 @@ asyncio.run(main())
513
513
  ```
514
514
 
515
515
 
516
- New in v0.3.0: Web3 & On-Chain Agent Capabilities
516
+ ## New in v0.3.0: Web3 & On-Chain Agent Capabilities
517
517
  CLAP now includes a powerful toolkit for building autonomous agents that can interact directly with EVM-compatible blockchains like Ethereum. Your agents can now hold assets, execute transactions, and interact with smart contracts, opening up a new world of possibilities in DeFi, DAOs, and on-chain automation.
518
518
  Setup
519
519
  To enable Web3 capabilities, install the web3 extra:
520
+ ```
520
521
  pip install "clap-agents[web3]"
521
- Use code with caution.
522
- Bash
522
+ ```
523
+
523
524
  You will also need to set the following variables in your .env file:
525
+ ```
524
526
  # Your connection to the blockchain (e.g., from Alchemy or Infura)
525
527
  WEB3_PROVIDER_URL="https://sepolia.infura.io/v3/YOUR_API_KEY"
526
528
 
527
529
  # The private key for your agent's wallet.
528
530
  # WARNING: For testing only. Do not use a key with real funds.
529
531
  AGENT_PRIVATE_KEY="0xYourTestnetPrivateKeyHere"
532
+ ```
530
533
 
531
534
 
532
-
533
- # Core Web3 Tools
535
+ ## Core Web3 Tools
534
536
  The framework now includes a suite of pre-built, robust tools for on-chain interaction:
535
537
 
536
538
  get_erc20_balance: Checks the balance of any standard ERC-20 token in a wallet.
@@ -544,9 +546,10 @@ get_token_price: Fetches real-time asset prices from on-chain Chainlink oracles,
544
546
  interact_with_contract: A powerful, generic tool to call any function on any smart contract, given its address and ABI.
545
547
 
546
548
 
547
- # Quick Start: A Simple DeFi Agent
549
+ ## Quick Start: A Simple DeFi Agent
548
550
  This example demonstrates an agent that can wrap ETH and then swap it for another token, a common DeFi task.
549
- # examples/simple_defi_agent.py
551
+ ```
552
+
550
553
  import os
551
554
  import asyncio
552
555
  from dotenv import load_dotenv
@@ -585,7 +588,7 @@ async def main():
585
588
 
586
589
  if __name__ == "__main__":
587
590
  asyncio.run(main())
588
-
591
+ ```
589
592
 
590
593
  This new capability transforms your CLAP agents from simple observers into active participants in the decentralized economy.
591
594
 
@@ -604,4 +607,3 @@ License
604
607
  This project is licensed under the terms of the Apache License 2.0. See the LICENSE file for details.
605
608
 
606
609
 
607
-
@@ -1,27 +1,27 @@
1
- clap/__init__.py,sha256=rxxESl-xpSZpM4ZIh-GvHYF74CkQdbe-dSLvhMC_2dQ,1069
1
+ clap/__init__.py,sha256=1U3LyIQ60FOOFKLNmdjqNMgN0rbNOO6ggNcDVTMz5SI,1081
2
2
  clap/embedding/__init__.py,sha256=PqnqcSiA_JwEvn69g2DCQHdsffL2l4GNEKo0fAtCqbs,520
3
3
  clap/embedding/base_embedding.py,sha256=0SYicQ-A-rSDqHoFK0IOrRQe0cisOl8OBnis6V43Chs,696
4
- clap/embedding/fastembed_embedding.py,sha256=V03b8bnSk1wtjJq5qlM9iksQnH6bnxrgXK8KbaEvxaQ,2882
4
+ clap/embedding/fastembed_embedding.py,sha256=fUXCRyctPxwinAG2JCkdmlARU945z7dEsXScIkpqwb0,2862
5
5
  clap/embedding/ollama_embedding.py,sha256=s7IYFs4BuM114Md1cqxim5WzCwCjbEJ48wAZZOgR7KQ,3702
6
6
  clap/embedding/sentence_transformer_embedding.py,sha256=0RAqGxDpjZVwerOLmVirqqnCwC07kHdfAPiy2fgOSCk,1798
7
- clap/llm_services/__init__.py,sha256=js__xIlkbXBLd2q1trYKjATYWa4xLNgPwwJz2Flwi0s,532
8
- clap/llm_services/base.py,sha256=BjSBVOtPMvPZJjI3HwSSI3OvVFyxd5HeOKLI9bN6P7M,2204
7
+ clap/llm_services/__init__.py,sha256=IBvWmE99PGxHq5Dt4u0G1erZSV80QEC981UULnrD6Tk,496
8
+ clap/llm_services/base.py,sha256=-XKWd6gLAXedIhUUqM_f7sqkVxdfifP2j-BwmF0hUkI,2183
9
9
  clap/llm_services/google_openai_compat_service.py,sha256=vN0osfCS6DIFHsCCiB03mKUp4n7SkIJd2PAypBAnC30,4552
10
10
  clap/llm_services/groq_service.py,sha256=pcTp24_NgLfp3bGaABzli_Sey7wZsXvFI74VjZ1GvkQ,3051
11
- clap/llm_services/ollama_service.py,sha256=gpWENKh4bhJh5VfIr7hmuqNOq-s1Zodvx8ws70vmq70,5305
11
+ clap/llm_services/ollama_service.py,sha256=Qh3W2fb-NDMVB8DS9o3q4jisZvK9U6s-r4ATNbAwVLE,5333
12
12
  clap/mcp_client/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
- clap/mcp_client/client.py,sha256=skIWhwkHnRXjlHwBvKXNZD5yQDe1iRIjrikn7WwczGM,8713
13
+ clap/mcp_client/client.py,sha256=MqcGEVe04B1vH0EGFaqXAEMCh_0C851MDr9hzGEBIM8,11729
14
14
  clap/multiagent_pattern/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
15
- clap/multiagent_pattern/agent.py,sha256=5wT1sy9IRZxMiqzj1ew7CbFFc03tIOExjxNb8y441bc,8533
15
+ clap/multiagent_pattern/agent.py,sha256=SDebwxaUquFUN_MMCGSYKLIIA3a6tVIls-IGrnEKqJI,8617
16
16
  clap/multiagent_pattern/team.py,sha256=t8Xru3fVPblw75pyuPT1wmI3jlsrZHD_GKAW5APbpFg,7966
17
17
  clap/react_pattern/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
18
18
  clap/react_pattern/react_agent.py,sha256=v9JYyIwv0vzkOl6kq8Aua7u50rJyU02NomCHTjt24vo,24596
19
19
  clap/tool_pattern/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
20
- clap/tool_pattern/tool.py,sha256=7fHkLTPafsAWr_ECXZKpQz0zzqEAxSrQ56ns5oWcBSU,5964
20
+ clap/tool_pattern/tool.py,sha256=Y4Uvu5FsCA3S3BZfjM3OOKfhA-o5Q9SfhCzGWfGIQ6o,5974
21
21
  clap/tool_pattern/tool_agent.py,sha256=VTQv9DNU16zgINZKVcX5oDw1lPfw5Y_8bUnW6wad2vE,14439
22
22
  clap/tools/__init__.py,sha256=8UMtxaPkq-pEOD2C0Qm4WZoyJpMxEOEQSDhWNLwAAiI,822
23
23
  clap/tools/email_tools.py,sha256=18aAlbjcSaOzpf9R3H-EGeRsqL5gdzmcJJcW619xOHU,9729
24
- clap/tools/web3_tools.py,sha256=N5enOoEVMx0T7TjB15NtEYt-_KcAdkm3C-UN0_QLVoo,12894
24
+ clap/tools/web3_tools.py,sha256=bb9zqhXYima6LzLARh8zgPx_gV0m9g0rf8ZqazCx-og,11852
25
25
  clap/tools/web_crawler.py,sha256=WdFbAKhUsUVveJimmLbzQ6k1BhOdMsg87FjL628HEKM,3542
26
26
  clap/tools/web_search.py,sha256=YT0I1kPrdxMUst-dpsGqqF6aqxMgj3ACwiW_jN9Pu9s,985
27
27
  clap/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -33,7 +33,7 @@ clap/vector_stores/__init__.py,sha256=H3w5jLdQFbXArVgiidy4RlAalM8a6LAiMlAX0Z-2v7
33
33
  clap/vector_stores/base.py,sha256=nvk8J1oNG3OKFhJfxBGFyVeh9YxoDs9RkB_iOzPBm1w,2853
34
34
  clap/vector_stores/chroma_store.py,sha256=vwkWWGxPwuW45T1PS6D44dXhDG9U_KZWjrMZCOkEXsA,7242
35
35
  clap/vector_stores/qdrant_store.py,sha256=-SwMTb0yaGngpQ9AddDzDIt3x8GZevlFT-0FMkWD28I,9923
36
- clap_agents-0.3.0.dist-info/METADATA,sha256=XPkseVTiOmoXluFd0CxYS7r37i7OyHhcm6EiMRk1ZYU,30573
37
- clap_agents-0.3.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
38
- clap_agents-0.3.0.dist-info/licenses/LICENSE,sha256=WNHhf_5RCaeuKWyq_K39vmp9F28LxKsB4SpomwSZ2L0,11357
39
- clap_agents-0.3.0.dist-info/RECORD,,
36
+ clap_agents-0.3.2.dist-info/METADATA,sha256=HcN7nnvyCWF3YxREc6BmAoscQ5vpe0UWSRnz99qeKeQ,30541
37
+ clap_agents-0.3.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
38
+ clap_agents-0.3.2.dist-info/licenses/LICENSE,sha256=WNHhf_5RCaeuKWyq_K39vmp9F28LxKsB4SpomwSZ2L0,11357
39
+ clap_agents-0.3.2.dist-info/RECORD,,