alita-sdk 0.3.176__py3-none-any.whl → 0.3.177__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.
Files changed (41) hide show
  1. alita_sdk/community/__init__.py +7 -17
  2. alita_sdk/tools/carrier/api_wrapper.py +6 -0
  3. alita_sdk/tools/carrier/backend_tests_tool.py +308 -7
  4. alita_sdk/tools/carrier/carrier_sdk.py +18 -0
  5. alita_sdk/tools/carrier/tools.py +2 -1
  6. {alita_sdk-0.3.176.dist-info → alita_sdk-0.3.177.dist-info}/METADATA +1 -2
  7. {alita_sdk-0.3.176.dist-info → alita_sdk-0.3.177.dist-info}/RECORD +10 -41
  8. alita_sdk/community/browseruse/__init__.py +0 -73
  9. alita_sdk/community/browseruse/api_wrapper.py +0 -288
  10. alita_sdk/community/deep_researcher/__init__.py +0 -70
  11. alita_sdk/community/deep_researcher/agents/__init__.py +0 -1
  12. alita_sdk/community/deep_researcher/agents/baseclass.py +0 -182
  13. alita_sdk/community/deep_researcher/agents/knowledge_gap_agent.py +0 -74
  14. alita_sdk/community/deep_researcher/agents/long_writer_agent.py +0 -251
  15. alita_sdk/community/deep_researcher/agents/planner_agent.py +0 -124
  16. alita_sdk/community/deep_researcher/agents/proofreader_agent.py +0 -80
  17. alita_sdk/community/deep_researcher/agents/thinking_agent.py +0 -64
  18. alita_sdk/community/deep_researcher/agents/tool_agents/__init__.py +0 -20
  19. alita_sdk/community/deep_researcher/agents/tool_agents/crawl_agent.py +0 -87
  20. alita_sdk/community/deep_researcher/agents/tool_agents/search_agent.py +0 -96
  21. alita_sdk/community/deep_researcher/agents/tool_selector_agent.py +0 -83
  22. alita_sdk/community/deep_researcher/agents/utils/__init__.py +0 -0
  23. alita_sdk/community/deep_researcher/agents/utils/parse_output.py +0 -148
  24. alita_sdk/community/deep_researcher/agents/writer_agent.py +0 -63
  25. alita_sdk/community/deep_researcher/api_wrapper.py +0 -116
  26. alita_sdk/community/deep_researcher/deep_research.py +0 -185
  27. alita_sdk/community/deep_researcher/examples/deep_example.py +0 -30
  28. alita_sdk/community/deep_researcher/examples/iterative_example.py +0 -34
  29. alita_sdk/community/deep_researcher/examples/report_plan_example.py +0 -27
  30. alita_sdk/community/deep_researcher/iterative_research.py +0 -419
  31. alita_sdk/community/deep_researcher/llm_config.py +0 -87
  32. alita_sdk/community/deep_researcher/main.py +0 -67
  33. alita_sdk/community/deep_researcher/tools/__init__.py +0 -2
  34. alita_sdk/community/deep_researcher/tools/crawl_website.py +0 -109
  35. alita_sdk/community/deep_researcher/tools/web_search.py +0 -294
  36. alita_sdk/community/deep_researcher/utils/__init__.py +0 -0
  37. alita_sdk/community/deep_researcher/utils/md_to_pdf.py +0 -8
  38. alita_sdk/community/deep_researcher/utils/os.py +0 -21
  39. {alita_sdk-0.3.176.dist-info → alita_sdk-0.3.177.dist-info}/WHEEL +0 -0
  40. {alita_sdk-0.3.176.dist-info → alita_sdk-0.3.177.dist-info}/licenses/LICENSE +0 -0
  41. {alita_sdk-0.3.176.dist-info → alita_sdk-0.3.177.dist-info}/top_level.txt +0 -0
@@ -1,96 +0,0 @@
1
- """
2
- Agent used to perform web searches and summarize the results.
3
-
4
- The SearchAgent takes as input a string in the format of AgentTask.model_dump_json(), or can take a simple query string as input
5
-
6
- The Agent then:
7
- 1. Uses the web_search tool to retrieve search results
8
- 2. Analyzes the retrieved information
9
- 3. Writes a 3+ paragraph summary of the search results
10
- 4. Includes citations/URLs in brackets next to information sources
11
- 5. Returns the formatted summary as a string
12
-
13
- The agent can use either OpenAI's built-in web search capability or a custom
14
- web search implementation based on environment configuration.
15
- """
16
-
17
- from langchain_core.tools import Tool
18
- from typing import Dict, Any, List
19
-
20
- from . import ToolAgentOutput
21
- from ...llm_config import LLMConfig
22
- from ..baseclass import ResearchAgent
23
- from ..utils.parse_output import create_type_parser
24
-
25
- INSTRUCTIONS = f"""You are a research assistant that specializes in retrieving and summarizing information from the web.
26
-
27
- OBJECTIVE:
28
- Given an AgentTask, follow these steps:
29
- - Convert the 'query' into an optimized SERP search term for Google, limited to 3-5 words
30
- - If an 'entity_website' is provided, make sure to include the domain name in your optimized Google search term
31
- - Enter the optimized search term into the web_search tool
32
- - After using the web_search tool, write a 3+ paragraph summary that captures the main points from the search results
33
-
34
- GUIDELINES:
35
- - In your summary, try to comprehensively answer/address the 'gap' provided (which is the objective of the search)
36
- - The summary should always quote detailed facts, figures and numbers where these are available
37
- - If the search results are not relevant to the search term or do not address the 'gap', simply write "No relevant results found"
38
- - Use headings and bullets to organize the summary if needed
39
- - Include citations/URLs in brackets next to all associated information in your summary
40
- - Do not make additional searches
41
-
42
- Only output JSON. Follow the JSON schema below. Do not output anything else. I will be parsing this with Pydantic so output valid JSON only:
43
- {ToolAgentOutput.model_json_schema()}
44
- """
45
-
46
- def init_search_agent(config: LLMConfig) -> ResearchAgent:
47
- """
48
- Initialize a search agent using LangChain tools.
49
-
50
- Args:
51
- config: The LLM configuration to use
52
-
53
- Returns:
54
- A ResearchAgent that can search the web and summarize results
55
- """
56
- # Create a LangChain wrapper around the web_search tool
57
- async def web_search_wrapper(query: str, num_results: int = 8) -> List[Dict[str, Any]]:
58
- """
59
- Perform a web search and return the results.
60
-
61
- Args:
62
- query: The query to search for
63
- num_results: Number of results to return
64
-
65
- Returns:
66
- A list of search results with title, url, and snippet
67
- """
68
- # Import here to avoid circular imports
69
- from ...tools import web_search
70
-
71
- # Use the original web_search function
72
- results = await web_search(query, num_results)
73
- return results
74
-
75
- # Create a LangChain Tool
76
- web_search_tool = Tool(
77
- name="web_search",
78
- description="Search the web for information on a specific query. Returns a list of search results.",
79
- func=web_search_wrapper,
80
- coroutine=web_search_wrapper,
81
- )
82
-
83
- # Use our adapter to initialize the agent with the LangChain tool
84
- selected_model = config.fast_model
85
-
86
- # Determine whether to use structured output
87
- use_output_parser = not hasattr(selected_model, 'langchain_llm')
88
-
89
- return ResearchAgent(
90
- name="WebSearchAgent",
91
- instructions=INSTRUCTIONS,
92
- tools=[web_search_tool],
93
- model=selected_model.langchain_llm if hasattr(selected_model, 'langchain_llm') else selected_model,
94
- output_type=ToolAgentOutput if not use_output_parser else None,
95
- output_parser=create_type_parser(ToolAgentOutput) if use_output_parser else None
96
- )
@@ -1,83 +0,0 @@
1
- """
2
- Agent used to determine which specialized agents should be used to address knowledge gaps.
3
-
4
- The Agent takes as input a string in the following format:
5
- ===========================================================
6
- ORIGINAL QUERY: <original user query>
7
-
8
- KNOWLEDGE GAP TO ADDRESS: <knowledge gap that needs to be addressed>
9
-
10
- BACKGROUND CONTEXT: <supporting background context related to the original query>
11
-
12
- HISTORY OF ACTIONS, FINDINGS AND THOUGHTS: <a log of prior iterations of the research process>
13
- ===========================================================
14
-
15
- The Agent then:
16
- 1. Analyzes the knowledge gap to determine which agents are best suited to address it
17
- 2. Returns an AgentSelectionPlan object containing a list of AgentTask objects
18
-
19
- The available agents are:
20
- - WebSearchAgent: General web search for broad topics
21
- - SiteCrawlerAgent: Crawl the pages of a specific website to retrieve information about it
22
- """
23
-
24
- from pydantic import BaseModel, Field
25
- from typing import List, Optional
26
- from ..llm_config import LLMConfig, model_supports_structured_output
27
- from datetime import datetime
28
- from .baseclass import ResearchAgent
29
- from .utils.parse_output import create_type_parser
30
-
31
-
32
- class AgentTask(BaseModel):
33
- """A task for a specific agent to address knowledge gaps"""
34
- gap: Optional[str] = Field(description="The knowledge gap being addressed", default=None)
35
- agent: str = Field(description="The name of the agent to use")
36
- query: str = Field(description="The specific query for the agent")
37
- entity_website: Optional[str] = Field(description="The website of the entity being researched, if known", default=None)
38
-
39
-
40
- class AgentSelectionPlan(BaseModel):
41
- """Plan for which agents to use for knowledge gaps"""
42
- tasks: List[AgentTask] = Field(description="List of agent tasks to address knowledge gaps")
43
-
44
-
45
- INSTRUCTIONS = f"""
46
- You are an Tool Selector responsible for determining which specialized agents should address a knowledge gap in a research project.
47
- Today's date is {datetime.now().strftime("%Y-%m-%d")}.
48
-
49
- You will be given:
50
- 1. The original user query
51
- 2. A knowledge gap identified in the research
52
- 3. A full history of the tasks, actions, findings and thoughts you've made up until this point in the research process
53
-
54
- Your task is to decide:
55
- 1. Which specialized agents are best suited to address the gap
56
- 2. What specific queries should be given to the agents (keep this short - 3-6 words)
57
-
58
- Available specialized agents:
59
- - WebSearchAgent: General web search for broad topics (can be called multiple times with different queries)
60
- - SiteCrawlerAgent: Crawl the pages of a specific website to retrieve information about it - use this if you want to find out something about a particular company, entity or product
61
-
62
- Guidelines:
63
- - Aim to call at most 3 agents at a time in your final output
64
- - You can list the WebSearchAgent multiple times with different queries if needed to cover the full scope of the knowledge gap
65
- - Be specific and concise (3-6 words) with the agent queries - they should target exactly what information is needed
66
- - If you know the website or domain name of an entity being researched, always include it in the query
67
- - If a gap doesn't clearly match any agent's capability, default to the WebSearchAgent
68
- - Use the history of actions / tool calls as a guide - try not to repeat yourself if an approach didn't work previously
69
-
70
- Only output JSON. Follow the JSON schema below. Do not output anything else. I will be parsing this with Pydantic so output valid JSON only:
71
- {AgentSelectionPlan.model_json_schema()}
72
- """
73
-
74
- def init_tool_selector_agent(config: LLMConfig) -> ResearchAgent:
75
- selected_model = config.reasoning_model
76
-
77
- return ResearchAgent(
78
- name="ToolSelectorAgent",
79
- instructions=INSTRUCTIONS,
80
- model=selected_model,
81
- output_type=AgentSelectionPlan if model_supports_structured_output(selected_model) else None,
82
- output_parser=create_type_parser(AgentSelectionPlan) if not model_supports_structured_output(selected_model) else None
83
- )
@@ -1,148 +0,0 @@
1
- import json
2
- import re
3
- from typing import Type, Any, Callable, TypeVar
4
-
5
- from pydantic import BaseModel
6
-
7
- T = TypeVar('T', bound=BaseModel)
8
-
9
-
10
- class OutputParserError(Exception):
11
- """
12
- Exception raised when the output parser fails to parse the output.
13
- """
14
- def __init__(self, message, output=None):
15
- self.message = message
16
- self.output = output
17
- super().__init__(self.message)
18
-
19
- def __str__(self):
20
- if self.output:
21
- return f"{self.message}\nProblematic output: {self.output}"
22
- return self.message
23
-
24
-
25
- def find_json_in_string(string: str) -> str:
26
- """
27
- Method to extract all text in the left-most brace that appears in a string.
28
- Used to extract JSON from a string (note that this function does not validate the JSON).
29
-
30
- Example:
31
- string = "bla bla bla {this is {some} text{{}and it's sneaky}} because {it's} confusing"
32
- output = "{this is {some} text{{}and it's sneaky}}"
33
- """
34
- stack = 0
35
- start_index = None
36
-
37
- for i, c in enumerate(string):
38
- if c == '{':
39
- if stack == 0:
40
- start_index = i # Start index of the first '{'
41
- stack += 1 # Push to stack
42
- elif c == '}':
43
- stack -= 1 # Pop stack
44
- if stack == 0:
45
- # Return the substring from the start of the first '{' to the current '}'
46
- return string[start_index:i + 1] if start_index is not None else ""
47
-
48
- # If no complete set of braces is found, return an empty string
49
- return ""
50
-
51
-
52
- def parse_json_output(output: str) -> Any:
53
- """Take a string output and parse it as JSON"""
54
- # First try to load the string as JSON
55
- try:
56
- return json.loads(output)
57
- except json.JSONDecodeError as e:
58
- pass
59
-
60
- # If that fails, assume that the output is in a code block - remove the code block markers and try again
61
- parsed_output = output
62
- parsed_output = parsed_output.split("```")[1]
63
- parsed_output = parsed_output.split("```")[0]
64
- if parsed_output.startswith("json") or parsed_output.startswith("JSON"):
65
- parsed_output = parsed_output[4:].strip()
66
- try:
67
- return json.loads(parsed_output)
68
- except json.JSONDecodeError:
69
- pass
70
-
71
- # As a last attempt, try to manually find the JSON object in the output and parse it
72
- parsed_output = find_json_in_string(output)
73
- if parsed_output:
74
- try:
75
- return json.loads(parsed_output)
76
- except json.JSONDecodeError:
77
- raise OutputParserError(f"Failed to parse output as JSON", output)
78
-
79
- # If all fails, raise an error
80
- raise OutputParserError(f"Failed to parse output as JSON", output)
81
-
82
-
83
- def create_type_parser(model_class: Type[T]) -> Callable[[str], T]:
84
- """
85
- Creates a parser function that attempts to parse the output into the given model class.
86
- This handles various formats that might be returned by the LLM.
87
-
88
- Args:
89
- model_class: The Pydantic model class to parse the output into
90
-
91
- Returns:
92
- A function that takes a string and returns an instance of the model class
93
- """
94
- def parser(text: str) -> T:
95
- """
96
- Parse the output into the model class.
97
-
98
- Args:
99
- text: The text to parse
100
-
101
- Returns:
102
- An instance of the model class
103
- """
104
- # First try direct JSON parsing
105
- try:
106
- return model_class.model_validate_json(text)
107
- except Exception:
108
- pass
109
-
110
- # Try to extract JSON from markdown codeblocks
111
- json_match = re.search(r"```(?:json)?\n(.*?)\n```", text, re.DOTALL)
112
- if json_match:
113
- try:
114
- json_str = json_match.group(1).strip()
115
- return model_class.model_validate_json(json_str)
116
- except Exception:
117
- pass
118
-
119
- # Try to parse the entire text as a JSON object
120
- try:
121
- # Look for JSON-like patterns
122
- json_pattern = r"(\{.*\})"
123
- match = re.search(json_pattern, text, re.DOTALL)
124
- if match:
125
- json_str = match.group(1)
126
- parsed = json.loads(json_str)
127
- return model_class.model_validate(parsed)
128
- except Exception:
129
- pass
130
-
131
- # Fall back to creating an instance with the text as output
132
- try:
133
- # Check if model has 'output' field
134
- if 'output' in model_class.model_fields:
135
- return model_class(output=text)
136
- except Exception:
137
- pass
138
-
139
- # Last resort: just try to create an empty instance and set attributes
140
- try:
141
- instance = model_class()
142
- if hasattr(instance, 'output'):
143
- setattr(instance, 'output', text)
144
- return instance
145
- except Exception as e:
146
- raise ValueError(f"Could not parse output to {model_class.__name__}: {e}")
147
-
148
- return parser
@@ -1,63 +0,0 @@
1
- """
2
- Agent used to synthesize a final report based on provided findings.
3
-
4
- The WriterAgent takes as input a string in the following format:
5
- ===========================================================
6
- QUERY: <original user query>
7
-
8
- FINDINGS: <findings from the iterative research process>
9
- ===========================================================
10
-
11
- The Agent then:
12
- 1. Generates a comprehensive markdown report based on all available information
13
- 2. Includes proper citations for sources in the format [1], [2], etc.
14
- 3. Returns a string containing the markdown formatted report
15
- """
16
- from .baseclass import ResearchAgent
17
- from ..llm_config import LLMConfig
18
- from datetime import datetime
19
- from langchain_core.tools import BaseTool
20
-
21
- INSTRUCTIONS = f"""
22
- You are a senior researcher tasked with comprehensively answering a research query.
23
- Today's date is {datetime.now().strftime('%Y-%m-%d')}.
24
- You will be provided with the original query along with research findings put together by a research assistant.
25
- Your objective is to generate the final response in markdown format.
26
- The response should be as lengthy and detailed as possible with the information provided, focusing on answering the original query.
27
- In your final output, include references to the source URLs for all information and data gathered.
28
- This should be formatted in the form of a numbered square bracket next to the relevant information,
29
- followed by a list of URLs at the end of the response, per the example below.
30
-
31
- EXAMPLE REFERENCE FORMAT:
32
- The company has XYZ products [1]. It operates in the software services market which is expected to grow at 10% per year [2].
33
-
34
- References:
35
- [1] https://example.com/first-source-url
36
- [2] https://example.com/second-source-url
37
-
38
- GUIDELINES:
39
- * Answer the query directly, do not include unrelated or tangential information.
40
- * Adhere to any instructions on the length of your final response if provided in the user prompt.
41
- * If any additional guidelines are provided in the user prompt, follow them exactly and give them precedence over these system instructions.
42
- """
43
-
44
- def init_writer_agent(config: LLMConfig) -> ResearchAgent:
45
- """
46
- Initialize the writer agent.
47
-
48
- Args:
49
- config: The LLM configuration to use
50
-
51
- Returns:
52
- A ResearchAgent that can generate comprehensive research reports
53
- """
54
- selected_model = config.main_model
55
-
56
- return ResearchAgent(
57
- name="WriterAgent",
58
- instructions=INSTRUCTIONS,
59
- tools=[], # No tools needed for this agent
60
- model=selected_model.langchain_llm if hasattr(selected_model, 'langchain_llm') else selected_model,
61
- output_type=None, # Direct string output
62
- output_parser=None
63
- )
@@ -1,116 +0,0 @@
1
- from typing import Any, Optional, Dict
2
- import asyncio
3
- import json
4
- from pydantic import create_model, Field
5
-
6
- from alita_sdk.tools.elitea_base import BaseToolApiWrapper
7
- from .deep_research import DeepResearcher
8
- from .iterative_research import IterativeResearcher
9
- from .llm_config import LLMConfig, create_default_config
10
- from langchain_core.language_models.llms import BaseLLM
11
- from langchain_core.language_models.chat_models import BaseChatModel
12
-
13
-
14
- class DeepResearcherWrapper(BaseToolApiWrapper):
15
- """Wrapper for deep_researcher module to be used as a LangChain toolkit."""
16
- alita: Any = None
17
- llm: Optional[BaseLLM | BaseChatModel] = None
18
- max_iterations: int = 5
19
- max_time_minutes: int = 10
20
- verbose: bool = False
21
- tracing: bool = False
22
- config: Optional[LLMConfig] = None
23
-
24
- def __init__(self, **kwargs):
25
- super().__init__(**kwargs)
26
- # Initialize the config if not provided
27
- if not self.config:
28
- self.config = create_default_config(langchain_llm=self.llm)
29
- # Override llm in config if provided
30
- elif self.llm and not self.config.langchain_llm:
31
- # Create a new config with the langchain_llm
32
- self.config = create_default_config(langchain_llm=self.llm)
33
-
34
- def _setup_deep_researcher(self) -> DeepResearcher:
35
- """Initialize a DeepResearcher instance with current settings."""
36
- return DeepResearcher(
37
- max_iterations=self.max_iterations,
38
- max_time_minutes=self.max_time_minutes,
39
- verbose=self.verbose,
40
- tracing=self.tracing,
41
- config=self.config,
42
- llm=self.llm,
43
- alita=self.alita
44
- )
45
-
46
- def _setup_iterative_researcher(self) -> IterativeResearcher:
47
- """Initialize an IterativeResearcher instance with current settings."""
48
- return IterativeResearcher(
49
- max_iterations=self.max_iterations,
50
- max_time_minutes=self.max_time_minutes,
51
- verbose=self.verbose,
52
- tracing=self.tracing,
53
- config=self.config,
54
- llm=self.llm,
55
- alita=self.alita
56
- )
57
-
58
- def run_deep_research(self, query: str) -> str:
59
- """
60
- Run deep research on a query, breaking it down into sections and iteratively researching each part.
61
-
62
- Args:
63
- query: The research query
64
-
65
- Returns:
66
- Comprehensive research report
67
- """
68
- researcher = self._setup_deep_researcher()
69
- return asyncio.run(researcher.run(query))
70
-
71
- def run_iterative_research(self, query: str, output_length: str = "5 pages", output_instructions: str = "", background_context: str = "") -> str:
72
- """
73
- Run iterative research on a query, conducting multiple iterations to address knowledge gaps.
74
-
75
- Args:
76
- query: The research query
77
- output_length: Desired length of the output (e.g., "5 pages", "2 paragraphs")
78
- output_instructions: Additional instructions for output formatting
79
- background_context: Additional context to provide for the research
80
-
81
- Returns:
82
- Research report based on iterative findings
83
- """
84
- researcher = self._setup_iterative_researcher()
85
- return asyncio.run(researcher.run(
86
- query=query,
87
- output_length=output_length,
88
- output_instructions=output_instructions,
89
- background_context=background_context
90
- ))
91
-
92
- def get_available_tools(self):
93
- """Return the list of available tools."""
94
- return [
95
- {
96
- "name": "run_deep_research",
97
- "ref": self.run_deep_research,
98
- "description": self.run_deep_research.__doc__,
99
- "args_schema": create_model(
100
- "DeepResearchModel",
101
- query=(str, Field(description="The research query to investigate thoroughly"))
102
- )
103
- },
104
- {
105
- "name": "run_iterative_research",
106
- "ref": self.run_iterative_research,
107
- "description": self.run_iterative_research.__doc__,
108
- "args_schema": create_model(
109
- "IterativeResearchModel",
110
- query=(str, Field(description="The research query to investigate")),
111
- output_length=(str, Field(description="Desired length of the output (e.g., '5 pages', '2 paragraphs')", default="5 pages")),
112
- output_instructions=(str, Field(description="Additional instructions for output formatting", default="")),
113
- background_context=(str, Field(description="Additional context to provide for the research", default=""))
114
- )
115
- }
116
- ]