langchain-agent-toolbox 0.1.0__tar.gz

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.
@@ -0,0 +1,251 @@
1
+ Metadata-Version: 2.4
2
+ Name: langchain-agent-toolbox
3
+ Version: 0.1.0
4
+ Summary: LangChain integration for Agent Toolbox API — search, extract, screenshot, weather, finance, email validation, and translation tools for AI agents
5
+ Author-email: Agent Toolbox <hello@agenttoolbox.dev>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/Vincentwei1021/agent-toolbox
8
+ Project-URL: Repository, https://github.com/Vincentwei1021/agent-toolbox/tree/master/integrations/langchain
9
+ Project-URL: Documentation, https://github.com/Vincentwei1021/agent-toolbox#readme
10
+ Project-URL: Issues, https://github.com/Vincentwei1021/agent-toolbox/issues
11
+ Keywords: langchain,ai-agent,tools,mcp,search,web-scraping,screenshot,weather,finance,email-validation,translation
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.9
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Topic :: Software Development :: Libraries
21
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
22
+ Requires-Python: >=3.9
23
+ Description-Content-Type: text/markdown
24
+ Requires-Dist: langchain-core>=0.2.0
25
+ Requires-Dist: httpx>=0.25.0
26
+
27
+ # 🧰 langchain-agent-toolbox
28
+
29
+ [![PyPI version](https://img.shields.io/badge/pypi-v0.1.0-blue)](https://pypi.org/project/langchain-agent-toolbox/)
30
+ [![License: MIT](https://img.shields.io/badge/license-MIT-green)](https://github.com/Vincentwei1021/agent-toolbox/blob/master/LICENSE)
31
+
32
+ **LangChain integration for [Agent Toolbox API](https://github.com/Vincentwei1021/agent-toolbox)** — 7 tools giving your LangChain agents real-world superpowers.
33
+
34
+ | Tool | Endpoint | Description |
35
+ |------|----------|-------------|
36
+ | `AgentToolboxSearchTool` | `/v1/search` | Web search via DuckDuckGo |
37
+ | `AgentToolboxExtractTool` | `/v1/extract` | Extract content from any URL |
38
+ | `AgentToolboxScreenshotTool` | `/v1/screenshot` | Capture web page screenshots |
39
+ | `AgentToolboxWeatherTool` | `/v1/weather` | Current weather & forecasts |
40
+ | `AgentToolboxFinanceTool` | `/v1/finance` | Stock quotes & exchange rates |
41
+ | `AgentToolboxEmailValidatorTool` | `/v1/validate-email` | Email validation (MX + SMTP + disposable) |
42
+ | `AgentToolboxTranslateTool` | `/v1/translate` | Translation with auto-detect & glossary |
43
+
44
+ ## Installation
45
+
46
+ ```bash
47
+ pip install langchain-agent-toolbox
48
+ ```
49
+
50
+ ## Quick Start
51
+
52
+ ### Get an API Key
53
+
54
+ ```bash
55
+ curl -X POST https://api.sendtoclaw.com/v1/auth/register \
56
+ -H "Content-Type: application/json" \
57
+ -d '{"email": "you@example.com"}'
58
+ ```
59
+
60
+ ### Set Environment Variable
61
+
62
+ ```bash
63
+ export AGENT_TOOLBOX_API_KEY="atb_your_key_here"
64
+ ```
65
+
66
+ ### Use with LangChain
67
+
68
+ ```python
69
+ from langchain_agent_toolbox import AgentToolboxSearchTool, AgentToolboxWeatherTool
70
+
71
+ # Initialize tools
72
+ search = AgentToolboxSearchTool()
73
+ weather = AgentToolboxWeatherTool()
74
+
75
+ # Use directly
76
+ results = search.invoke({"query": "latest AI news", "count": 3})
77
+ print(results)
78
+
79
+ forecast = weather.invoke({"location": "Tokyo"})
80
+ print(forecast)
81
+ ```
82
+
83
+ ### Use with a LangChain Agent
84
+
85
+ ```python
86
+ from langchain_openai import ChatOpenAI
87
+ from langchain.agents import AgentExecutor, create_tool_calling_agent
88
+ from langchain_core.prompts import ChatPromptTemplate
89
+ from langchain_agent_toolbox import (
90
+ AgentToolboxSearchTool,
91
+ AgentToolboxExtractTool,
92
+ AgentToolboxWeatherTool,
93
+ AgentToolboxTranslateTool,
94
+ )
95
+
96
+ # Initialize tools
97
+ tools = [
98
+ AgentToolboxSearchTool(),
99
+ AgentToolboxExtractTool(),
100
+ AgentToolboxWeatherTool(),
101
+ AgentToolboxTranslateTool(),
102
+ ]
103
+
104
+ # Create agent
105
+ llm = ChatOpenAI(model="gpt-4o")
106
+ prompt = ChatPromptTemplate.from_messages([
107
+ ("system", "You are a helpful assistant with access to web tools."),
108
+ ("human", "{input}"),
109
+ ("placeholder", "{agent_scratchpad}"),
110
+ ])
111
+
112
+ agent = create_tool_calling_agent(llm, tools, prompt)
113
+ executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
114
+
115
+ # Run
116
+ result = executor.invoke({
117
+ "input": "What's the weather in Paris? Also search for top restaurants there."
118
+ })
119
+ print(result["output"])
120
+ ```
121
+
122
+ ### Translation with Glossary
123
+
124
+ ```python
125
+ from langchain_agent_toolbox import AgentToolboxTranslateTool
126
+
127
+ translate = AgentToolboxTranslateTool()
128
+
129
+ # Simple translation
130
+ result = translate.invoke({
131
+ "text": "Hello, how are you?",
132
+ "target": "zh",
133
+ })
134
+ print(result) # 你好,你好吗?
135
+
136
+ # With glossary (preserve technical terms)
137
+ result = translate.invoke({
138
+ "text": "The API endpoint returns JSON data.",
139
+ "target": "zh",
140
+ "glossary": {"API": "API", "JSON": "JSON", "endpoint": "端点"},
141
+ })
142
+ print(result) # API 端点 返回 JSON 数据。
143
+ ```
144
+
145
+ ### Email Validation
146
+
147
+ ```python
148
+ from langchain_agent_toolbox import AgentToolboxEmailValidatorTool
149
+
150
+ validator = AgentToolboxEmailValidatorTool()
151
+
152
+ result = validator.invoke({"email": "test@gmail.com"})
153
+ print(result)
154
+ # {
155
+ # "email": "test@gmail.com",
156
+ # "valid_syntax": true,
157
+ # "mx_found": true,
158
+ # "is_disposable": false,
159
+ # "verdict": "deliverable",
160
+ # "score": 0.95
161
+ # }
162
+ ```
163
+
164
+ ### Finance: Stocks & Exchange Rates
165
+
166
+ ```python
167
+ from langchain_agent_toolbox import AgentToolboxFinanceTool
168
+
169
+ finance = AgentToolboxFinanceTool()
170
+
171
+ # Stock quote
172
+ quote = finance.invoke({"symbol": "AAPL"})
173
+ print(quote)
174
+
175
+ # Currency exchange
176
+ rate = finance.invoke({
177
+ "from_currency": "USD",
178
+ "to_currency": "EUR",
179
+ "amount": 100,
180
+ "type": "exchange",
181
+ })
182
+ print(rate)
183
+ ```
184
+
185
+ ## Configuration
186
+
187
+ ### API Key
188
+
189
+ Set via environment variable (recommended):
190
+
191
+ ```bash
192
+ export AGENT_TOOLBOX_API_KEY="atb_your_key_here"
193
+ ```
194
+
195
+ Or pass directly:
196
+
197
+ ```python
198
+ tool = AgentToolboxSearchTool(api_key="atb_your_key_here")
199
+ ```
200
+
201
+ ### Custom Base URL
202
+
203
+ For self-hosted instances:
204
+
205
+ ```python
206
+ tool = AgentToolboxSearchTool(
207
+ api_key="your-key",
208
+ base_url="http://localhost:3100",
209
+ )
210
+ ```
211
+
212
+ Or via environment variable:
213
+
214
+ ```bash
215
+ export AGENT_TOOLBOX_BASE_URL="http://localhost:3100"
216
+ ```
217
+
218
+ ## Async Support
219
+
220
+ All tools support async out of the box:
221
+
222
+ ```python
223
+ import asyncio
224
+ from langchain_agent_toolbox import AgentToolboxSearchTool
225
+
226
+ async def main():
227
+ search = AgentToolboxSearchTool()
228
+ result = await search.ainvoke({"query": "async python", "count": 3})
229
+ print(result)
230
+
231
+ asyncio.run(main())
232
+ ```
233
+
234
+ ## API Reference
235
+
236
+ All tools accept these common parameters:
237
+
238
+ | Parameter | Type | Default | Description |
239
+ |-----------|------|---------|-------------|
240
+ | `api_key` | `str` | `$AGENT_TOOLBOX_API_KEY` | API key for authentication |
241
+ | `base_url` | `str` | `https://api.sendtoclaw.com` | API base URL |
242
+
243
+ ## Links
244
+
245
+ - [Agent Toolbox API](https://github.com/Vincentwei1021/agent-toolbox) — main project
246
+ - [OpenAPI Spec](https://api.sendtoclaw.com/v1/docs) — full API documentation
247
+ - [LangChain](https://python.langchain.com/) — LangChain framework
248
+
249
+ ## License
250
+
251
+ MIT
@@ -0,0 +1,225 @@
1
+ # 🧰 langchain-agent-toolbox
2
+
3
+ [![PyPI version](https://img.shields.io/badge/pypi-v0.1.0-blue)](https://pypi.org/project/langchain-agent-toolbox/)
4
+ [![License: MIT](https://img.shields.io/badge/license-MIT-green)](https://github.com/Vincentwei1021/agent-toolbox/blob/master/LICENSE)
5
+
6
+ **LangChain integration for [Agent Toolbox API](https://github.com/Vincentwei1021/agent-toolbox)** — 7 tools giving your LangChain agents real-world superpowers.
7
+
8
+ | Tool | Endpoint | Description |
9
+ |------|----------|-------------|
10
+ | `AgentToolboxSearchTool` | `/v1/search` | Web search via DuckDuckGo |
11
+ | `AgentToolboxExtractTool` | `/v1/extract` | Extract content from any URL |
12
+ | `AgentToolboxScreenshotTool` | `/v1/screenshot` | Capture web page screenshots |
13
+ | `AgentToolboxWeatherTool` | `/v1/weather` | Current weather & forecasts |
14
+ | `AgentToolboxFinanceTool` | `/v1/finance` | Stock quotes & exchange rates |
15
+ | `AgentToolboxEmailValidatorTool` | `/v1/validate-email` | Email validation (MX + SMTP + disposable) |
16
+ | `AgentToolboxTranslateTool` | `/v1/translate` | Translation with auto-detect & glossary |
17
+
18
+ ## Installation
19
+
20
+ ```bash
21
+ pip install langchain-agent-toolbox
22
+ ```
23
+
24
+ ## Quick Start
25
+
26
+ ### Get an API Key
27
+
28
+ ```bash
29
+ curl -X POST https://api.sendtoclaw.com/v1/auth/register \
30
+ -H "Content-Type: application/json" \
31
+ -d '{"email": "you@example.com"}'
32
+ ```
33
+
34
+ ### Set Environment Variable
35
+
36
+ ```bash
37
+ export AGENT_TOOLBOX_API_KEY="atb_your_key_here"
38
+ ```
39
+
40
+ ### Use with LangChain
41
+
42
+ ```python
43
+ from langchain_agent_toolbox import AgentToolboxSearchTool, AgentToolboxWeatherTool
44
+
45
+ # Initialize tools
46
+ search = AgentToolboxSearchTool()
47
+ weather = AgentToolboxWeatherTool()
48
+
49
+ # Use directly
50
+ results = search.invoke({"query": "latest AI news", "count": 3})
51
+ print(results)
52
+
53
+ forecast = weather.invoke({"location": "Tokyo"})
54
+ print(forecast)
55
+ ```
56
+
57
+ ### Use with a LangChain Agent
58
+
59
+ ```python
60
+ from langchain_openai import ChatOpenAI
61
+ from langchain.agents import AgentExecutor, create_tool_calling_agent
62
+ from langchain_core.prompts import ChatPromptTemplate
63
+ from langchain_agent_toolbox import (
64
+ AgentToolboxSearchTool,
65
+ AgentToolboxExtractTool,
66
+ AgentToolboxWeatherTool,
67
+ AgentToolboxTranslateTool,
68
+ )
69
+
70
+ # Initialize tools
71
+ tools = [
72
+ AgentToolboxSearchTool(),
73
+ AgentToolboxExtractTool(),
74
+ AgentToolboxWeatherTool(),
75
+ AgentToolboxTranslateTool(),
76
+ ]
77
+
78
+ # Create agent
79
+ llm = ChatOpenAI(model="gpt-4o")
80
+ prompt = ChatPromptTemplate.from_messages([
81
+ ("system", "You are a helpful assistant with access to web tools."),
82
+ ("human", "{input}"),
83
+ ("placeholder", "{agent_scratchpad}"),
84
+ ])
85
+
86
+ agent = create_tool_calling_agent(llm, tools, prompt)
87
+ executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
88
+
89
+ # Run
90
+ result = executor.invoke({
91
+ "input": "What's the weather in Paris? Also search for top restaurants there."
92
+ })
93
+ print(result["output"])
94
+ ```
95
+
96
+ ### Translation with Glossary
97
+
98
+ ```python
99
+ from langchain_agent_toolbox import AgentToolboxTranslateTool
100
+
101
+ translate = AgentToolboxTranslateTool()
102
+
103
+ # Simple translation
104
+ result = translate.invoke({
105
+ "text": "Hello, how are you?",
106
+ "target": "zh",
107
+ })
108
+ print(result) # 你好,你好吗?
109
+
110
+ # With glossary (preserve technical terms)
111
+ result = translate.invoke({
112
+ "text": "The API endpoint returns JSON data.",
113
+ "target": "zh",
114
+ "glossary": {"API": "API", "JSON": "JSON", "endpoint": "端点"},
115
+ })
116
+ print(result) # API 端点 返回 JSON 数据。
117
+ ```
118
+
119
+ ### Email Validation
120
+
121
+ ```python
122
+ from langchain_agent_toolbox import AgentToolboxEmailValidatorTool
123
+
124
+ validator = AgentToolboxEmailValidatorTool()
125
+
126
+ result = validator.invoke({"email": "test@gmail.com"})
127
+ print(result)
128
+ # {
129
+ # "email": "test@gmail.com",
130
+ # "valid_syntax": true,
131
+ # "mx_found": true,
132
+ # "is_disposable": false,
133
+ # "verdict": "deliverable",
134
+ # "score": 0.95
135
+ # }
136
+ ```
137
+
138
+ ### Finance: Stocks & Exchange Rates
139
+
140
+ ```python
141
+ from langchain_agent_toolbox import AgentToolboxFinanceTool
142
+
143
+ finance = AgentToolboxFinanceTool()
144
+
145
+ # Stock quote
146
+ quote = finance.invoke({"symbol": "AAPL"})
147
+ print(quote)
148
+
149
+ # Currency exchange
150
+ rate = finance.invoke({
151
+ "from_currency": "USD",
152
+ "to_currency": "EUR",
153
+ "amount": 100,
154
+ "type": "exchange",
155
+ })
156
+ print(rate)
157
+ ```
158
+
159
+ ## Configuration
160
+
161
+ ### API Key
162
+
163
+ Set via environment variable (recommended):
164
+
165
+ ```bash
166
+ export AGENT_TOOLBOX_API_KEY="atb_your_key_here"
167
+ ```
168
+
169
+ Or pass directly:
170
+
171
+ ```python
172
+ tool = AgentToolboxSearchTool(api_key="atb_your_key_here")
173
+ ```
174
+
175
+ ### Custom Base URL
176
+
177
+ For self-hosted instances:
178
+
179
+ ```python
180
+ tool = AgentToolboxSearchTool(
181
+ api_key="your-key",
182
+ base_url="http://localhost:3100",
183
+ )
184
+ ```
185
+
186
+ Or via environment variable:
187
+
188
+ ```bash
189
+ export AGENT_TOOLBOX_BASE_URL="http://localhost:3100"
190
+ ```
191
+
192
+ ## Async Support
193
+
194
+ All tools support async out of the box:
195
+
196
+ ```python
197
+ import asyncio
198
+ from langchain_agent_toolbox import AgentToolboxSearchTool
199
+
200
+ async def main():
201
+ search = AgentToolboxSearchTool()
202
+ result = await search.ainvoke({"query": "async python", "count": 3})
203
+ print(result)
204
+
205
+ asyncio.run(main())
206
+ ```
207
+
208
+ ## API Reference
209
+
210
+ All tools accept these common parameters:
211
+
212
+ | Parameter | Type | Default | Description |
213
+ |-----------|------|---------|-------------|
214
+ | `api_key` | `str` | `$AGENT_TOOLBOX_API_KEY` | API key for authentication |
215
+ | `base_url` | `str` | `https://api.sendtoclaw.com` | API base URL |
216
+
217
+ ## Links
218
+
219
+ - [Agent Toolbox API](https://github.com/Vincentwei1021/agent-toolbox) — main project
220
+ - [OpenAPI Spec](https://api.sendtoclaw.com/v1/docs) — full API documentation
221
+ - [LangChain](https://python.langchain.com/) — LangChain framework
222
+
223
+ ## License
224
+
225
+ MIT
@@ -0,0 +1,23 @@
1
+ """LangChain integration for Agent Toolbox API."""
2
+
3
+ from langchain_agent_toolbox.tools import (
4
+ AgentToolboxSearchTool,
5
+ AgentToolboxExtractTool,
6
+ AgentToolboxScreenshotTool,
7
+ AgentToolboxWeatherTool,
8
+ AgentToolboxFinanceTool,
9
+ AgentToolboxEmailValidatorTool,
10
+ AgentToolboxTranslateTool,
11
+ )
12
+
13
+ __all__ = [
14
+ "AgentToolboxSearchTool",
15
+ "AgentToolboxExtractTool",
16
+ "AgentToolboxScreenshotTool",
17
+ "AgentToolboxWeatherTool",
18
+ "AgentToolboxFinanceTool",
19
+ "AgentToolboxEmailValidatorTool",
20
+ "AgentToolboxTranslateTool",
21
+ ]
22
+
23
+ __version__ = "0.1.0"
@@ -0,0 +1,48 @@
1
+ """HTTP client for Agent Toolbox API."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any, Dict, Optional
6
+
7
+ import httpx
8
+
9
+
10
+ DEFAULT_BASE_URL = "https://api.sendtoclaw.com"
11
+ DEFAULT_TIMEOUT = 30.0
12
+
13
+
14
+ class AgentToolboxClient:
15
+ """Thin HTTP client for the Agent Toolbox REST API."""
16
+
17
+ def __init__(
18
+ self,
19
+ api_key: str,
20
+ base_url: str = DEFAULT_BASE_URL,
21
+ timeout: float = DEFAULT_TIMEOUT,
22
+ ) -> None:
23
+ self.api_key = api_key
24
+ self.base_url = base_url.rstrip("/")
25
+ self.timeout = timeout
26
+
27
+ def _headers(self) -> Dict[str, str]:
28
+ return {
29
+ "Authorization": f"Bearer {self.api_key}",
30
+ "x-api-key": self.api_key,
31
+ "Content-Type": "application/json",
32
+ }
33
+
34
+ def post(self, endpoint: str, payload: Dict[str, Any]) -> Dict[str, Any]:
35
+ """Synchronous POST request."""
36
+ url = f"{self.base_url}{endpoint}"
37
+ with httpx.Client(timeout=self.timeout) as client:
38
+ resp = client.post(url, json=payload, headers=self._headers())
39
+ resp.raise_for_status()
40
+ return resp.json()
41
+
42
+ async def apost(self, endpoint: str, payload: Dict[str, Any]) -> Dict[str, Any]:
43
+ """Async POST request."""
44
+ url = f"{self.base_url}{endpoint}"
45
+ async with httpx.AsyncClient(timeout=self.timeout) as client:
46
+ resp = await client.post(url, json=payload, headers=self._headers())
47
+ resp.raise_for_status()
48
+ return resp.json()
@@ -0,0 +1,364 @@
1
+ """LangChain tools for Agent Toolbox API."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import json
6
+ import os
7
+ from typing import Any, Dict, List, Optional, Type
8
+
9
+ from langchain_core.callbacks import (
10
+ AsyncCallbackManagerForToolRun,
11
+ CallbackManagerForToolRun,
12
+ )
13
+ from langchain_core.tools import BaseTool
14
+ from pydantic import BaseModel, Field
15
+
16
+ from langchain_agent_toolbox.client import AgentToolboxClient, DEFAULT_BASE_URL
17
+
18
+
19
+ def _get_client(
20
+ api_key: Optional[str] = None,
21
+ base_url: Optional[str] = None,
22
+ ) -> AgentToolboxClient:
23
+ key = api_key or os.environ.get("AGENT_TOOLBOX_API_KEY", "")
24
+ if not key:
25
+ raise ValueError(
26
+ "Agent Toolbox API key is required. "
27
+ "Pass api_key= or set AGENT_TOOLBOX_API_KEY env var."
28
+ )
29
+ url = base_url or os.environ.get("AGENT_TOOLBOX_BASE_URL", DEFAULT_BASE_URL)
30
+ return AgentToolboxClient(api_key=key, base_url=url)
31
+
32
+
33
+ # ---------------------------------------------------------------------------
34
+ # Search
35
+ # ---------------------------------------------------------------------------
36
+
37
+ class SearchInput(BaseModel):
38
+ query: str = Field(description="Search query string")
39
+ count: int = Field(default=5, description="Number of results (1-10)")
40
+
41
+
42
+ class AgentToolboxSearchTool(BaseTool):
43
+ """Search the web using Agent Toolbox API (DuckDuckGo backend)."""
44
+
45
+ name: str = "agent_toolbox_search"
46
+ description: str = (
47
+ "Search the web and get titles, URLs, and snippets. "
48
+ "Useful for finding up-to-date information on any topic."
49
+ )
50
+ args_schema: Type[BaseModel] = SearchInput
51
+ api_key: Optional[str] = None
52
+ base_url: Optional[str] = None
53
+
54
+ def _run(
55
+ self,
56
+ query: str,
57
+ count: int = 5,
58
+ run_manager: Optional[CallbackManagerForToolRun] = None,
59
+ ) -> str:
60
+ client = _get_client(self.api_key, self.base_url)
61
+ result = client.post("/v1/search", {"query": query, "count": count})
62
+ return json.dumps(result.get("data", []), indent=2)
63
+
64
+ async def _arun(
65
+ self,
66
+ query: str,
67
+ count: int = 5,
68
+ run_manager: Optional[AsyncCallbackManagerForToolRun] = None,
69
+ ) -> str:
70
+ client = _get_client(self.api_key, self.base_url)
71
+ result = await client.apost("/v1/search", {"query": query, "count": count})
72
+ return json.dumps(result.get("data", []), indent=2)
73
+
74
+
75
+ # ---------------------------------------------------------------------------
76
+ # Extract
77
+ # ---------------------------------------------------------------------------
78
+
79
+ class ExtractInput(BaseModel):
80
+ url: str = Field(description="URL to extract content from")
81
+ format: str = Field(default="markdown", description="Output format: markdown, text, or json")
82
+
83
+
84
+ class AgentToolboxExtractTool(BaseTool):
85
+ """Extract readable content from a web page."""
86
+
87
+ name: str = "agent_toolbox_extract"
88
+ description: str = (
89
+ "Extract the main readable content from a web page URL. "
90
+ "Returns clean text/markdown, removing ads and navigation."
91
+ )
92
+ args_schema: Type[BaseModel] = ExtractInput
93
+ api_key: Optional[str] = None
94
+ base_url: Optional[str] = None
95
+
96
+ def _run(
97
+ self,
98
+ url: str,
99
+ format: str = "markdown",
100
+ run_manager: Optional[CallbackManagerForToolRun] = None,
101
+ ) -> str:
102
+ client = _get_client(self.api_key, self.base_url)
103
+ result = client.post("/v1/extract", {"url": url, "format": format})
104
+ data = result.get("data", {})
105
+ return data.get("content", json.dumps(data, indent=2))
106
+
107
+ async def _arun(
108
+ self,
109
+ url: str,
110
+ format: str = "markdown",
111
+ run_manager: Optional[AsyncCallbackManagerForToolRun] = None,
112
+ ) -> str:
113
+ client = _get_client(self.api_key, self.base_url)
114
+ result = await client.apost("/v1/extract", {"url": url, "format": format})
115
+ data = result.get("data", {})
116
+ return data.get("content", json.dumps(data, indent=2))
117
+
118
+
119
+ # ---------------------------------------------------------------------------
120
+ # Screenshot
121
+ # ---------------------------------------------------------------------------
122
+
123
+ class ScreenshotInput(BaseModel):
124
+ url: str = Field(description="URL to screenshot")
125
+ width: int = Field(default=1280, description="Viewport width in pixels")
126
+ height: int = Field(default=720, description="Viewport height in pixels")
127
+
128
+
129
+ class AgentToolboxScreenshotTool(BaseTool):
130
+ """Take a screenshot of a web page."""
131
+
132
+ name: str = "agent_toolbox_screenshot"
133
+ description: str = (
134
+ "Capture a screenshot of a web page. "
135
+ "Returns base64-encoded PNG image data."
136
+ )
137
+ args_schema: Type[BaseModel] = ScreenshotInput
138
+ api_key: Optional[str] = None
139
+ base_url: Optional[str] = None
140
+
141
+ def _run(
142
+ self,
143
+ url: str,
144
+ width: int = 1280,
145
+ height: int = 720,
146
+ run_manager: Optional[CallbackManagerForToolRun] = None,
147
+ ) -> str:
148
+ client = _get_client(self.api_key, self.base_url)
149
+ result = client.post("/v1/screenshot", {"url": url, "width": width, "height": height})
150
+ return json.dumps(result.get("data", {}), indent=2)
151
+
152
+ async def _arun(
153
+ self,
154
+ url: str,
155
+ width: int = 1280,
156
+ height: int = 720,
157
+ run_manager: Optional[AsyncCallbackManagerForToolRun] = None,
158
+ ) -> str:
159
+ client = _get_client(self.api_key, self.base_url)
160
+ result = await client.apost("/v1/screenshot", {"url": url, "width": width, "height": height})
161
+ return json.dumps(result.get("data", {}), indent=2)
162
+
163
+
164
+ # ---------------------------------------------------------------------------
165
+ # Weather
166
+ # ---------------------------------------------------------------------------
167
+
168
+ class WeatherInput(BaseModel):
169
+ location: str = Field(description="City name or location")
170
+
171
+
172
+ class AgentToolboxWeatherTool(BaseTool):
173
+ """Get current weather and forecast for a location."""
174
+
175
+ name: str = "agent_toolbox_weather"
176
+ description: str = (
177
+ "Get current weather conditions and forecast for any location. "
178
+ "Returns temperature, humidity, wind, and multi-day forecast."
179
+ )
180
+ args_schema: Type[BaseModel] = WeatherInput
181
+ api_key: Optional[str] = None
182
+ base_url: Optional[str] = None
183
+
184
+ def _run(
185
+ self,
186
+ location: str,
187
+ run_manager: Optional[CallbackManagerForToolRun] = None,
188
+ ) -> str:
189
+ client = _get_client(self.api_key, self.base_url)
190
+ result = client.post("/v1/weather", {"location": location})
191
+ return json.dumps(result.get("data", {}), indent=2)
192
+
193
+ async def _arun(
194
+ self,
195
+ location: str,
196
+ run_manager: Optional[AsyncCallbackManagerForToolRun] = None,
197
+ ) -> str:
198
+ client = _get_client(self.api_key, self.base_url)
199
+ result = await client.apost("/v1/weather", {"location": location})
200
+ return json.dumps(result.get("data", {}), indent=2)
201
+
202
+
203
+ # ---------------------------------------------------------------------------
204
+ # Finance
205
+ # ---------------------------------------------------------------------------
206
+
207
+ class FinanceInput(BaseModel):
208
+ symbol: Optional[str] = Field(default=None, description="Stock ticker symbol (e.g. AAPL)")
209
+ type: Optional[str] = Field(default="quote", description="Request type: quote or exchange")
210
+ from_currency: Optional[str] = Field(default=None, description="Source currency code (for exchange)", alias="from")
211
+ to_currency: Optional[str] = Field(default=None, description="Target currency code (for exchange)", alias="to")
212
+ amount: Optional[float] = Field(default=None, description="Amount to convert (for exchange)")
213
+
214
+ class Config:
215
+ populate_by_name = True
216
+
217
+
218
+ class AgentToolboxFinanceTool(BaseTool):
219
+ """Get stock quotes or currency exchange rates."""
220
+
221
+ name: str = "agent_toolbox_finance"
222
+ description: str = (
223
+ "Get real-time stock quotes or currency exchange rates. "
224
+ "For stocks: provide symbol (e.g. 'AAPL'). "
225
+ "For exchange rates: provide from, to, and amount."
226
+ )
227
+ args_schema: Type[BaseModel] = FinanceInput
228
+ api_key: Optional[str] = None
229
+ base_url: Optional[str] = None
230
+
231
+ def _run(
232
+ self,
233
+ symbol: Optional[str] = None,
234
+ type: Optional[str] = "quote",
235
+ from_currency: Optional[str] = None,
236
+ to_currency: Optional[str] = None,
237
+ amount: Optional[float] = None,
238
+ run_manager: Optional[CallbackManagerForToolRun] = None,
239
+ **kwargs: Any,
240
+ ) -> str:
241
+ client = _get_client(self.api_key, self.base_url)
242
+ payload: Dict[str, Any] = {}
243
+ if symbol:
244
+ payload = {"symbol": symbol, "type": type or "quote"}
245
+ elif from_currency and to_currency:
246
+ payload = {"from": from_currency, "to": to_currency, "amount": amount or 1}
247
+ result = client.post("/v1/finance", payload)
248
+ return json.dumps(result.get("data", {}), indent=2)
249
+
250
+ async def _arun(
251
+ self,
252
+ symbol: Optional[str] = None,
253
+ type: Optional[str] = "quote",
254
+ from_currency: Optional[str] = None,
255
+ to_currency: Optional[str] = None,
256
+ amount: Optional[float] = None,
257
+ run_manager: Optional[AsyncCallbackManagerForToolRun] = None,
258
+ **kwargs: Any,
259
+ ) -> str:
260
+ client = _get_client(self.api_key, self.base_url)
261
+ payload: Dict[str, Any] = {}
262
+ if symbol:
263
+ payload = {"symbol": symbol, "type": type or "quote"}
264
+ elif from_currency and to_currency:
265
+ payload = {"from": from_currency, "to": to_currency, "amount": amount or 1}
266
+ result = await client.apost("/v1/finance", payload)
267
+ return json.dumps(result.get("data", {}), indent=2)
268
+
269
+
270
+ # ---------------------------------------------------------------------------
271
+ # Email Validator
272
+ # ---------------------------------------------------------------------------
273
+
274
+ class EmailValidatorInput(BaseModel):
275
+ email: str = Field(description="Email address to validate")
276
+
277
+
278
+ class AgentToolboxEmailValidatorTool(BaseTool):
279
+ """Validate an email address (syntax, MX, SMTP, disposable check)."""
280
+
281
+ name: str = "agent_toolbox_email_validator"
282
+ description: str = (
283
+ "Validate an email address by checking syntax, MX records, "
284
+ "SMTP reachability, and disposable domain detection. "
285
+ "Returns a verdict: deliverable, risky, undeliverable, or invalid."
286
+ )
287
+ args_schema: Type[BaseModel] = EmailValidatorInput
288
+ api_key: Optional[str] = None
289
+ base_url: Optional[str] = None
290
+
291
+ def _run(
292
+ self,
293
+ email: str,
294
+ run_manager: Optional[CallbackManagerForToolRun] = None,
295
+ ) -> str:
296
+ client = _get_client(self.api_key, self.base_url)
297
+ result = client.post("/v1/validate-email", {"email": email})
298
+ return json.dumps(result.get("data", {}), indent=2)
299
+
300
+ async def _arun(
301
+ self,
302
+ email: str,
303
+ run_manager: Optional[AsyncCallbackManagerForToolRun] = None,
304
+ ) -> str:
305
+ client = _get_client(self.api_key, self.base_url)
306
+ result = await client.apost("/v1/validate-email", {"email": email})
307
+ return json.dumps(result.get("data", {}), indent=2)
308
+
309
+
310
+ # ---------------------------------------------------------------------------
311
+ # Translate
312
+ # ---------------------------------------------------------------------------
313
+
314
+ class TranslateInput(BaseModel):
315
+ text: str = Field(description="Text to translate")
316
+ target: str = Field(description="Target language code (e.g. zh, ja, es, fr)")
317
+ source: str = Field(default="auto", description="Source language code or 'auto'")
318
+ glossary: Optional[Dict[str, str]] = Field(default=None, description="Optional glossary: {term: translation}")
319
+
320
+
321
+ class AgentToolboxTranslateTool(BaseTool):
322
+ """Translate text between 100+ languages."""
323
+
324
+ name: str = "agent_toolbox_translate"
325
+ description: str = (
326
+ "Translate text between languages with automatic language detection. "
327
+ "Supports glossary for preserving specific terms. "
328
+ "Provide target language code (e.g. 'zh' for Chinese, 'ja' for Japanese)."
329
+ )
330
+ args_schema: Type[BaseModel] = TranslateInput
331
+ api_key: Optional[str] = None
332
+ base_url: Optional[str] = None
333
+
334
+ def _run(
335
+ self,
336
+ text: str,
337
+ target: str,
338
+ source: str = "auto",
339
+ glossary: Optional[Dict[str, str]] = None,
340
+ run_manager: Optional[CallbackManagerForToolRun] = None,
341
+ ) -> str:
342
+ client = _get_client(self.api_key, self.base_url)
343
+ payload: Dict[str, Any] = {"text": text, "target": target, "source": source}
344
+ if glossary:
345
+ payload["glossary"] = glossary
346
+ result = client.post("/v1/translate", payload)
347
+ data = result.get("data", {})
348
+ return data.get("translation", json.dumps(data, indent=2))
349
+
350
+ async def _arun(
351
+ self,
352
+ text: str,
353
+ target: str,
354
+ source: str = "auto",
355
+ glossary: Optional[Dict[str, str]] = None,
356
+ run_manager: Optional[AsyncCallbackManagerForToolRun] = None,
357
+ ) -> str:
358
+ client = _get_client(self.api_key, self.base_url)
359
+ payload: Dict[str, Any] = {"text": text, "target": target, "source": source}
360
+ if glossary:
361
+ payload["glossary"] = glossary
362
+ result = await client.apost("/v1/translate", payload)
363
+ data = result.get("data", {})
364
+ return data.get("translation", json.dumps(data, indent=2))
@@ -0,0 +1,251 @@
1
+ Metadata-Version: 2.4
2
+ Name: langchain-agent-toolbox
3
+ Version: 0.1.0
4
+ Summary: LangChain integration for Agent Toolbox API — search, extract, screenshot, weather, finance, email validation, and translation tools for AI agents
5
+ Author-email: Agent Toolbox <hello@agenttoolbox.dev>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/Vincentwei1021/agent-toolbox
8
+ Project-URL: Repository, https://github.com/Vincentwei1021/agent-toolbox/tree/master/integrations/langchain
9
+ Project-URL: Documentation, https://github.com/Vincentwei1021/agent-toolbox#readme
10
+ Project-URL: Issues, https://github.com/Vincentwei1021/agent-toolbox/issues
11
+ Keywords: langchain,ai-agent,tools,mcp,search,web-scraping,screenshot,weather,finance,email-validation,translation
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.9
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Topic :: Software Development :: Libraries
21
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
22
+ Requires-Python: >=3.9
23
+ Description-Content-Type: text/markdown
24
+ Requires-Dist: langchain-core>=0.2.0
25
+ Requires-Dist: httpx>=0.25.0
26
+
27
+ # 🧰 langchain-agent-toolbox
28
+
29
+ [![PyPI version](https://img.shields.io/badge/pypi-v0.1.0-blue)](https://pypi.org/project/langchain-agent-toolbox/)
30
+ [![License: MIT](https://img.shields.io/badge/license-MIT-green)](https://github.com/Vincentwei1021/agent-toolbox/blob/master/LICENSE)
31
+
32
+ **LangChain integration for [Agent Toolbox API](https://github.com/Vincentwei1021/agent-toolbox)** — 7 tools giving your LangChain agents real-world superpowers.
33
+
34
+ | Tool | Endpoint | Description |
35
+ |------|----------|-------------|
36
+ | `AgentToolboxSearchTool` | `/v1/search` | Web search via DuckDuckGo |
37
+ | `AgentToolboxExtractTool` | `/v1/extract` | Extract content from any URL |
38
+ | `AgentToolboxScreenshotTool` | `/v1/screenshot` | Capture web page screenshots |
39
+ | `AgentToolboxWeatherTool` | `/v1/weather` | Current weather & forecasts |
40
+ | `AgentToolboxFinanceTool` | `/v1/finance` | Stock quotes & exchange rates |
41
+ | `AgentToolboxEmailValidatorTool` | `/v1/validate-email` | Email validation (MX + SMTP + disposable) |
42
+ | `AgentToolboxTranslateTool` | `/v1/translate` | Translation with auto-detect & glossary |
43
+
44
+ ## Installation
45
+
46
+ ```bash
47
+ pip install langchain-agent-toolbox
48
+ ```
49
+
50
+ ## Quick Start
51
+
52
+ ### Get an API Key
53
+
54
+ ```bash
55
+ curl -X POST https://api.sendtoclaw.com/v1/auth/register \
56
+ -H "Content-Type: application/json" \
57
+ -d '{"email": "you@example.com"}'
58
+ ```
59
+
60
+ ### Set Environment Variable
61
+
62
+ ```bash
63
+ export AGENT_TOOLBOX_API_KEY="atb_your_key_here"
64
+ ```
65
+
66
+ ### Use with LangChain
67
+
68
+ ```python
69
+ from langchain_agent_toolbox import AgentToolboxSearchTool, AgentToolboxWeatherTool
70
+
71
+ # Initialize tools
72
+ search = AgentToolboxSearchTool()
73
+ weather = AgentToolboxWeatherTool()
74
+
75
+ # Use directly
76
+ results = search.invoke({"query": "latest AI news", "count": 3})
77
+ print(results)
78
+
79
+ forecast = weather.invoke({"location": "Tokyo"})
80
+ print(forecast)
81
+ ```
82
+
83
+ ### Use with a LangChain Agent
84
+
85
+ ```python
86
+ from langchain_openai import ChatOpenAI
87
+ from langchain.agents import AgentExecutor, create_tool_calling_agent
88
+ from langchain_core.prompts import ChatPromptTemplate
89
+ from langchain_agent_toolbox import (
90
+ AgentToolboxSearchTool,
91
+ AgentToolboxExtractTool,
92
+ AgentToolboxWeatherTool,
93
+ AgentToolboxTranslateTool,
94
+ )
95
+
96
+ # Initialize tools
97
+ tools = [
98
+ AgentToolboxSearchTool(),
99
+ AgentToolboxExtractTool(),
100
+ AgentToolboxWeatherTool(),
101
+ AgentToolboxTranslateTool(),
102
+ ]
103
+
104
+ # Create agent
105
+ llm = ChatOpenAI(model="gpt-4o")
106
+ prompt = ChatPromptTemplate.from_messages([
107
+ ("system", "You are a helpful assistant with access to web tools."),
108
+ ("human", "{input}"),
109
+ ("placeholder", "{agent_scratchpad}"),
110
+ ])
111
+
112
+ agent = create_tool_calling_agent(llm, tools, prompt)
113
+ executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
114
+
115
+ # Run
116
+ result = executor.invoke({
117
+ "input": "What's the weather in Paris? Also search for top restaurants there."
118
+ })
119
+ print(result["output"])
120
+ ```
121
+
122
+ ### Translation with Glossary
123
+
124
+ ```python
125
+ from langchain_agent_toolbox import AgentToolboxTranslateTool
126
+
127
+ translate = AgentToolboxTranslateTool()
128
+
129
+ # Simple translation
130
+ result = translate.invoke({
131
+ "text": "Hello, how are you?",
132
+ "target": "zh",
133
+ })
134
+ print(result) # 你好,你好吗?
135
+
136
+ # With glossary (preserve technical terms)
137
+ result = translate.invoke({
138
+ "text": "The API endpoint returns JSON data.",
139
+ "target": "zh",
140
+ "glossary": {"API": "API", "JSON": "JSON", "endpoint": "端点"},
141
+ })
142
+ print(result) # API 端点 返回 JSON 数据。
143
+ ```
144
+
145
+ ### Email Validation
146
+
147
+ ```python
148
+ from langchain_agent_toolbox import AgentToolboxEmailValidatorTool
149
+
150
+ validator = AgentToolboxEmailValidatorTool()
151
+
152
+ result = validator.invoke({"email": "test@gmail.com"})
153
+ print(result)
154
+ # {
155
+ # "email": "test@gmail.com",
156
+ # "valid_syntax": true,
157
+ # "mx_found": true,
158
+ # "is_disposable": false,
159
+ # "verdict": "deliverable",
160
+ # "score": 0.95
161
+ # }
162
+ ```
163
+
164
+ ### Finance: Stocks & Exchange Rates
165
+
166
+ ```python
167
+ from langchain_agent_toolbox import AgentToolboxFinanceTool
168
+
169
+ finance = AgentToolboxFinanceTool()
170
+
171
+ # Stock quote
172
+ quote = finance.invoke({"symbol": "AAPL"})
173
+ print(quote)
174
+
175
+ # Currency exchange
176
+ rate = finance.invoke({
177
+ "from_currency": "USD",
178
+ "to_currency": "EUR",
179
+ "amount": 100,
180
+ "type": "exchange",
181
+ })
182
+ print(rate)
183
+ ```
184
+
185
+ ## Configuration
186
+
187
+ ### API Key
188
+
189
+ Set via environment variable (recommended):
190
+
191
+ ```bash
192
+ export AGENT_TOOLBOX_API_KEY="atb_your_key_here"
193
+ ```
194
+
195
+ Or pass directly:
196
+
197
+ ```python
198
+ tool = AgentToolboxSearchTool(api_key="atb_your_key_here")
199
+ ```
200
+
201
+ ### Custom Base URL
202
+
203
+ For self-hosted instances:
204
+
205
+ ```python
206
+ tool = AgentToolboxSearchTool(
207
+ api_key="your-key",
208
+ base_url="http://localhost:3100",
209
+ )
210
+ ```
211
+
212
+ Or via environment variable:
213
+
214
+ ```bash
215
+ export AGENT_TOOLBOX_BASE_URL="http://localhost:3100"
216
+ ```
217
+
218
+ ## Async Support
219
+
220
+ All tools support async out of the box:
221
+
222
+ ```python
223
+ import asyncio
224
+ from langchain_agent_toolbox import AgentToolboxSearchTool
225
+
226
+ async def main():
227
+ search = AgentToolboxSearchTool()
228
+ result = await search.ainvoke({"query": "async python", "count": 3})
229
+ print(result)
230
+
231
+ asyncio.run(main())
232
+ ```
233
+
234
+ ## API Reference
235
+
236
+ All tools accept these common parameters:
237
+
238
+ | Parameter | Type | Default | Description |
239
+ |-----------|------|---------|-------------|
240
+ | `api_key` | `str` | `$AGENT_TOOLBOX_API_KEY` | API key for authentication |
241
+ | `base_url` | `str` | `https://api.sendtoclaw.com` | API base URL |
242
+
243
+ ## Links
244
+
245
+ - [Agent Toolbox API](https://github.com/Vincentwei1021/agent-toolbox) — main project
246
+ - [OpenAPI Spec](https://api.sendtoclaw.com/v1/docs) — full API documentation
247
+ - [LangChain](https://python.langchain.com/) — LangChain framework
248
+
249
+ ## License
250
+
251
+ MIT
@@ -0,0 +1,12 @@
1
+ README.md
2
+ pyproject.toml
3
+ langchain_agent_toolbox/__init__.py
4
+ langchain_agent_toolbox/client.py
5
+ langchain_agent_toolbox/py.typed
6
+ langchain_agent_toolbox/tools.py
7
+ langchain_agent_toolbox.egg-info/PKG-INFO
8
+ langchain_agent_toolbox.egg-info/SOURCES.txt
9
+ langchain_agent_toolbox.egg-info/dependency_links.txt
10
+ langchain_agent_toolbox.egg-info/requires.txt
11
+ langchain_agent_toolbox.egg-info/top_level.txt
12
+ tests/test_tools.py
@@ -0,0 +1,2 @@
1
+ langchain-core>=0.2.0
2
+ httpx>=0.25.0
@@ -0,0 +1 @@
1
+ langchain_agent_toolbox
@@ -0,0 +1,40 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "langchain-agent-toolbox"
7
+ version = "0.1.0"
8
+ description = "LangChain integration for Agent Toolbox API — search, extract, screenshot, weather, finance, email validation, and translation tools for AI agents"
9
+ readme = "README.md"
10
+ license = {text = "MIT"}
11
+ requires-python = ">=3.9"
12
+ authors = [
13
+ {name = "Agent Toolbox", email = "hello@agenttoolbox.dev"},
14
+ ]
15
+ keywords = ["langchain", "ai-agent", "tools", "mcp", "search", "web-scraping", "screenshot", "weather", "finance", "email-validation", "translation"]
16
+ classifiers = [
17
+ "Development Status :: 4 - Beta",
18
+ "Intended Audience :: Developers",
19
+ "License :: OSI Approved :: MIT License",
20
+ "Programming Language :: Python :: 3",
21
+ "Programming Language :: Python :: 3.9",
22
+ "Programming Language :: Python :: 3.10",
23
+ "Programming Language :: Python :: 3.11",
24
+ "Programming Language :: Python :: 3.12",
25
+ "Topic :: Software Development :: Libraries",
26
+ "Topic :: Scientific/Engineering :: Artificial Intelligence",
27
+ ]
28
+ dependencies = [
29
+ "langchain-core>=0.2.0",
30
+ "httpx>=0.25.0",
31
+ ]
32
+
33
+ [project.urls]
34
+ Homepage = "https://github.com/Vincentwei1021/agent-toolbox"
35
+ Repository = "https://github.com/Vincentwei1021/agent-toolbox/tree/master/integrations/langchain"
36
+ Documentation = "https://github.com/Vincentwei1021/agent-toolbox#readme"
37
+ Issues = "https://github.com/Vincentwei1021/agent-toolbox/issues"
38
+
39
+ [tool.setuptools.packages.find]
40
+ include = ["langchain_agent_toolbox*"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,42 @@
1
+ """Basic import and instantiation tests for langchain-agent-toolbox."""
2
+
3
+ import os
4
+ import pytest
5
+
6
+
7
+ def test_imports():
8
+ from langchain_agent_toolbox import (
9
+ AgentToolboxSearchTool,
10
+ AgentToolboxExtractTool,
11
+ AgentToolboxScreenshotTool,
12
+ AgentToolboxWeatherTool,
13
+ AgentToolboxFinanceTool,
14
+ AgentToolboxEmailValidatorTool,
15
+ AgentToolboxTranslateTool,
16
+ )
17
+ assert AgentToolboxSearchTool is not None
18
+ assert AgentToolboxTranslateTool is not None
19
+
20
+
21
+ def test_tool_instantiation():
22
+ from langchain_agent_toolbox import AgentToolboxSearchTool
23
+ tool = AgentToolboxSearchTool(api_key="test-key")
24
+ assert tool.name == "agent_toolbox_search"
25
+ assert "search" in tool.description.lower()
26
+
27
+
28
+ def test_tool_schema():
29
+ from langchain_agent_toolbox import AgentToolboxTranslateTool
30
+ tool = AgentToolboxTranslateTool(api_key="test-key")
31
+ schema = tool.args_schema.model_json_schema()
32
+ assert "text" in schema["properties"]
33
+ assert "target" in schema["properties"]
34
+
35
+
36
+ def test_missing_api_key():
37
+ from langchain_agent_toolbox import AgentToolboxSearchTool
38
+ # Clear env var if set
39
+ os.environ.pop("AGENT_TOOLBOX_API_KEY", None)
40
+ tool = AgentToolboxSearchTool()
41
+ with pytest.raises(ValueError, match="API key is required"):
42
+ tool._run(query="test")