Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

linkup for agents #178

Open
wants to merge 14 commits into
base: main
Choose a base branch
from
103 changes: 49 additions & 54 deletions crewai_tools/tools/linkup/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,7 @@ The `LinkupSearchTool` is a tool designed for integration with the CrewAI framew

## Features

- Perform API queries to the Linkup platform using customizable parameters (`query`, `depth`, `output_type`).
- Gracefully handles API errors and provides structured feedback.
- Returns well-structured results for seamless integration into CrewAI processes.
- Perform API queries to the Linkup platform using customizable parameters (`query`, `depth`, `output_type`, `structured_output_schema`).

---

Expand All @@ -26,11 +24,6 @@ The `LinkupSearchTool` is a tool designed for integration with the CrewAI framew
pip install 'crewai[tools]'
```

2. Create a `.env` file in your project root and add your Linkup API Key:
```plaintext
LINKUP_API_KEY=your_linkup_api_key
```

---

## Usage
Expand All @@ -43,56 +36,58 @@ Here is how to use the `LinkupSearchTool` in a CrewAI project:
```python
from tools.linkup_tools import LinkupSearchTool
import os
from dotenv import load_dotenv
import json

load_dotenv()
os.environ["LINKUP_API_KEY"] = "your_linkup_api_key"
os.environ["OPENAI_API_KEY"] = "your_openai_api_key"
depth = "standard" # or deep
output_type = "sourcedAnswer" # or searchResults or structured

linkup_tool = LinkupSearchTool(api_key=os.getenv("LINKUP_API_KEY"))
```
# If output_type = structured, define a structured schema
structured_output_schema = {your schema}

2. **Set Up an Agent and Task**:
```python
from crewai import Agent, Task, Crew

# Define the agent
research_agent = Agent(
role="Information Researcher",
goal="Fetch relevant results from Linkup.",
backstory="An expert in online information retrieval...",
tools=[linkup_tool],
verbose=True
)

# Define the task
search_task = Task(
expected_output="A detailed list of Nobel Prize-winning women in physics with their achievements.",
description="Search for women who have won the Nobel Prize in Physics.",
agent=research_agent
)

# Create and run the crew
crew = Crew(
agents=[research_agent],
tasks=[search_task]
)

result = crew.kickoff()
print(result)
```
structured_output_schema_json = json.dumps(structured_output_schema)

### Advanced Configuration
# Initialize the Linkup search tool

You can customize the parameters for the `LinkupSearchTool`:
linkup_tool = LinkupSearchTool(
api_key=os.getenv("LINKUP_API_KEY"),
depth=depth,
output_type=output_type,
structured_output_schema=structured_output_schema_json # ONLY if output_type = structured
)

- `query`: The search term or phrase.
- `depth`: The search depth (`"standard"` by default).
- `output_type`: The type of output (`"searchResults"` by default).
```

Example:
```python
response = linkup_tool._run(
query="Women Nobel Prize Physics",
depth="standard",
output_type="searchResults"
)
```
2. **Set Up an Agent and Task**:
```python
from crewai import Agent, Task, Crew

# Create an agent
researcher = Agent(
role="Market Research Analyst",
goal="Provide deep insights using Linkup for AI industry trends.",
backstory="An experienced analyst skilled in using advanced tools for market insights.",
tools=[linkup_tool],
verbose=True, # change to False if you don't want to see execution logs
)

# Define a task
research = Task(
description="Research the latest trends in the AI industry using the Linkup tool and provide insights.",
expected_output="A summary of the top 3 trends with context and relevance to the industry.",
agent=researcher,
)



# Set up and execute the Crew
crew = Crew(
agents=[researcher],
tasks=[research],
verbose=True,
planning=True, # or False if you don't want to see planning logs
)
crew.kickoff()

```
Binary file removed crewai_tools/tools/linkup/assets/icon.png
Binary file not shown.
89 changes: 38 additions & 51 deletions crewai_tools/tools/linkup/linkup_search_tool.py
Original file line number Diff line number Diff line change
@@ -1,73 +1,60 @@
from typing import Any

from typing import Any, Type
from pydantic import BaseModel, Field
from crewai.tools import BaseTool

try:
from linkup import LinkupClient

LINKUP_AVAILABLE = True
except ImportError:
LINKUP_AVAILABLE = False
LinkupClient = Any # type placeholder when package is not available
LinkupClient = Any

from pydantic import PrivateAttr

class LinkupSearchToolSchema(BaseModel):
"""Input for LinkupBaseTool."""

query: str = Field(
..., description="The query to search for."
)


class LinkupSearchTool(BaseTool):
name: str = "Linkup Search Tool"
description: str = (
"Performs an API call to Linkup to retrieve contextual information."
)
_client: LinkupClient = PrivateAttr() # type: ignore
description: str = (
"Performs an API call to Linkup to retrieve contextual information."
)
_client: LinkupClient = PrivateAttr() # type: ignore
description: str = "A tool to search and retrieve trends or insights using the Linkup API."
args_schema: Type[BaseModel] = LinkupSearchToolSchema

def __init__(self, api_key: str):
"""
Initialize the tool with an API key.
"""
super().__init__()
try:
from linkup import LinkupClient
except ImportError:
import click

if click.confirm(
"You are missing the 'linkup-sdk' package. Would you like to install it?"
):
import subprocess
def __init__(self, api_key: str, depth: str, output_type: str, structured_output_schema:str = None, **kwargs):
from linkup import LinkupClient

subprocess.run(["uv", "add", "linkup-sdk"], check=True)
from linkup import LinkupClient
super().__init__(**kwargs)
if not LINKUP_AVAILABLE:
raise ImportError(
"The 'linkup' package is required to use the LinkupSearchTool. "
"Please install it with: pip install linkup"
)

else:
raise ImportError(
"The 'linkup-sdk' package is required to use the LinkupSearchTool. "
"Please install it with: uv add linkup-sdk"
)
self._client = LinkupClient(api_key=api_key)
self._default_depth = depth
self._default_output_type = output_type
self._default_structured_schema = structured_output_schema

def _run(self, query: str ) :

def _run(
self, query: str, depth: str = "standard", output_type: str = "searchResults"
) -> dict:
"""
Executes a search using the Linkup API.

:param query: The query to search for.
:param depth: Search depth (default is "standard").
:param output_type: Desired result type (default is "searchResults").
:return: A dictionary containing the results or an error message.
:return: The results or an error message.
"""
try:
response = self._client.search(
query=query, depth=depth, output_type=output_type
)
results = [
{"name": result.name, "url": result.url, "content": result.content}
for result in response.results
]
return {"success": True, "results": results}
except Exception as e:
return {"success": False, "error": str(e)}

api_params = {
"query": query,
"depth": self._default_depth,
"output_type": self._default_output_type,
}

if self._default_output_type == "structured":
if not self.structured_output_schema:
raise ValueError("structured_output_schema must be provided when output_type is 'structured'.")
api_params["structured_output_schema"] = self._default_structured_schema
return self._client.search(**api_params)
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ dependencies = [
"docker>=7.1.0",
"embedchain>=0.1.114",
"crewai>=0.95.0",
"linkup-sdk>=0.2.1",
Copy link

@BruceWouaigne BruceWouaigne Jan 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@juliette0704 can you update to 0.2.2 please

"click>=8.1.8",
"lancedb>=0.5.4",
]
Expand Down