aiagents4pharma 1.19.1__py3-none-any.whl → 1.20.1__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- aiagents4pharma/talk2biomodels/configs/config.yaml +5 -0
- aiagents4pharma/talk2scholars/agents/main_agent.py +129 -73
- aiagents4pharma/talk2scholars/agents/s2_agent.py +2 -1
- aiagents4pharma/talk2scholars/configs/agents/talk2scholars/main_agent/default.yaml +10 -31
- aiagents4pharma/talk2scholars/configs/agents/talk2scholars/s2_agent/default.yaml +16 -60
- aiagents4pharma/talk2scholars/state/state_talk2scholars.py +9 -8
- aiagents4pharma/talk2scholars/tests/test_integration.py +237 -0
- aiagents4pharma/talk2scholars/tests/test_main_agent.py +180 -0
- aiagents4pharma/talk2scholars/tests/test_s2_agent.py +138 -0
- aiagents4pharma/talk2scholars/tests/{test_langgraph.py → test_s2_tools.py} +79 -151
- aiagents4pharma/talk2scholars/tests/test_state.py +14 -0
- aiagents4pharma/talk2scholars/tools/s2/display_results.py +33 -8
- aiagents4pharma/talk2scholars/tools/s2/multi_paper_rec.py +10 -23
- aiagents4pharma/talk2scholars/tools/s2/search.py +10 -29
- aiagents4pharma/talk2scholars/tools/s2/single_paper_rec.py +4 -29
- {aiagents4pharma-1.19.1.dist-info → aiagents4pharma-1.20.1.dist-info}/METADATA +19 -3
- {aiagents4pharma-1.19.1.dist-info → aiagents4pharma-1.20.1.dist-info}/RECORD +20 -15
- {aiagents4pharma-1.19.1.dist-info → aiagents4pharma-1.20.1.dist-info}/LICENSE +0 -0
- {aiagents4pharma-1.19.1.dist-info → aiagents4pharma-1.20.1.dist-info}/WHEEL +0 -0
- {aiagents4pharma-1.19.1.dist-info → aiagents4pharma-1.20.1.dist-info}/top_level.txt +0 -0
@@ -1,151 +1,207 @@
|
|
1
1
|
#!/usr/bin/env python3
|
2
2
|
|
3
3
|
"""
|
4
|
-
Main agent for the talk2scholars app.
|
4
|
+
Main agent for the talk2scholars app using ReAct pattern.
|
5
|
+
|
6
|
+
This module implements a hierarchical agent system where a supervisor agent
|
7
|
+
routes queries to specialized sub-agents. It follows the LangGraph patterns
|
8
|
+
for multi-agent systems and implements proper state management.
|
9
|
+
|
10
|
+
The main components are:
|
11
|
+
1. Supervisor node with ReAct pattern for intelligent routing.
|
12
|
+
2. S2 agent node for handling academic paper queries.
|
13
|
+
3. Shared state management via Talk2Scholars.
|
14
|
+
4. Hydra-based configuration system.
|
15
|
+
|
16
|
+
Example:
|
17
|
+
app = get_app("thread_123", "gpt-4o-mini")
|
18
|
+
result = app.invoke({
|
19
|
+
"messages": [("human", "Find papers about AI agents")]
|
20
|
+
})
|
5
21
|
"""
|
6
22
|
|
7
23
|
import logging
|
8
|
-
from typing import Literal,
|
24
|
+
from typing import Literal, Callable
|
9
25
|
import hydra
|
10
26
|
from langchain_core.language_models.chat_models import BaseChatModel
|
11
|
-
from langchain_core.messages import AIMessage
|
12
27
|
from langchain_openai import ChatOpenAI
|
13
28
|
from langgraph.checkpoint.memory import MemorySaver
|
14
29
|
from langgraph.graph import END, START, StateGraph
|
30
|
+
from langgraph.prebuilt import create_react_agent
|
15
31
|
from langgraph.types import Command
|
16
32
|
from ..agents import s2_agent
|
17
33
|
from ..state.state_talk2scholars import Talk2Scholars
|
18
34
|
|
35
|
+
# Configure logging
|
19
36
|
logging.basicConfig(level=logging.INFO)
|
20
37
|
logger = logging.getLogger(__name__)
|
21
38
|
|
22
39
|
|
23
|
-
def
|
40
|
+
def get_hydra_config():
|
24
41
|
"""
|
25
|
-
|
42
|
+
Loads and returns the Hydra configuration for the main agent.
|
43
|
+
|
44
|
+
This function fetches the configuration settings for the Talk2Scholars
|
45
|
+
agent, ensuring that all required parameters are properly initialized.
|
46
|
+
|
47
|
+
Returns:
|
48
|
+
Any: The configuration object for the main agent.
|
49
|
+
"""
|
50
|
+
with hydra.initialize(version_base=None, config_path="../configs"):
|
51
|
+
cfg = hydra.compose(
|
52
|
+
config_name="config", overrides=["agents/talk2scholars/main_agent=default"]
|
53
|
+
)
|
54
|
+
return cfg.agents.talk2scholars.main_agent
|
55
|
+
|
56
|
+
|
57
|
+
def make_supervisor_node(llm: BaseChatModel, thread_id: str) -> Callable:
|
58
|
+
"""
|
59
|
+
Creates and returns a supervisor node for intelligent routing using the ReAct pattern.
|
60
|
+
|
61
|
+
This function initializes a supervisor agent that processes user queries and
|
62
|
+
determines the appropriate sub-agent for further processing. It applies structured
|
63
|
+
reasoning to manage conversations and direct queries based on context.
|
26
64
|
|
27
65
|
Args:
|
28
|
-
llm (BaseChatModel): The language model
|
29
|
-
|
66
|
+
llm (BaseChatModel): The language model used by the supervisor agent.
|
67
|
+
thread_id (str): Unique identifier for the conversation session.
|
30
68
|
|
31
69
|
Returns:
|
32
|
-
|
70
|
+
Callable: A function that acts as the supervisor node in the LangGraph workflow.
|
71
|
+
|
72
|
+
Example:
|
73
|
+
supervisor = make_supervisor_node(llm, "thread_123")
|
74
|
+
workflow.add_node("supervisor", supervisor)
|
33
75
|
"""
|
76
|
+
logger.info("Loading Hydra configuration for Talk2Scholars main agent.")
|
77
|
+
cfg = get_hydra_config()
|
78
|
+
logger.info("Hydra configuration loaded with values: %s", cfg)
|
79
|
+
|
80
|
+
# Create the supervisor agent using the main agent's configuration
|
81
|
+
supervisor_agent = create_react_agent(
|
82
|
+
llm,
|
83
|
+
tools=[], # Will add sub-agents later
|
84
|
+
state_modifier=cfg.main_agent,
|
85
|
+
state_schema=Talk2Scholars,
|
86
|
+
checkpointer=MemorySaver(),
|
87
|
+
)
|
88
|
+
|
34
89
|
def supervisor_node(
|
35
90
|
state: Talk2Scholars,
|
36
91
|
) -> Command[Literal["s2_agent", "__end__"]]:
|
37
92
|
"""
|
38
|
-
|
93
|
+
Processes user queries and determines the next step in the conversation flow.
|
94
|
+
|
95
|
+
This function examines the conversation state and decides whether to forward
|
96
|
+
the query to a specialized sub-agent (e.g., S2 agent) or conclude the interaction.
|
39
97
|
|
40
98
|
Args:
|
41
|
-
state (Talk2Scholars): The current state of the conversation
|
99
|
+
state (Talk2Scholars): The current state of the conversation, containing
|
100
|
+
messages, papers, and metadata.
|
42
101
|
|
43
102
|
Returns:
|
44
|
-
Command
|
103
|
+
Command: The next action to be executed, along with updated state data.
|
104
|
+
|
105
|
+
Example:
|
106
|
+
result = supervisor_node(current_state)
|
107
|
+
next_step = result.goto
|
45
108
|
"""
|
46
109
|
logger.info(
|
47
|
-
"Supervisor node called - Messages count: %d
|
110
|
+
"Supervisor node called - Messages count: %d",
|
48
111
|
len(state["messages"]),
|
49
|
-
state.get("current_agent", "None"),
|
50
112
|
)
|
51
113
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
response = llm.invoke(messages)
|
56
|
-
goto = (
|
57
|
-
"FINISH"
|
58
|
-
if not any(
|
59
|
-
kw in state["messages"][-1].content.lower()
|
60
|
-
for kw in ["search", "paper", "find"]
|
61
|
-
)
|
62
|
-
else "s2_agent"
|
114
|
+
# Invoke the supervisor agent with configurable thread_id
|
115
|
+
result = supervisor_agent.invoke(
|
116
|
+
state, {"configurable": {"thread_id": thread_id}}
|
63
117
|
)
|
118
|
+
goto = "s2_agent"
|
119
|
+
logger.info("Supervisor agent completed with result: %s", result)
|
64
120
|
|
65
|
-
|
66
|
-
return Command(
|
67
|
-
goto=END,
|
68
|
-
update={
|
69
|
-
"messages": state["messages"]
|
70
|
-
+ [AIMessage(content=response.content)],
|
71
|
-
"is_last_step": True,
|
72
|
-
"current_agent": None,
|
73
|
-
},
|
74
|
-
)
|
75
|
-
|
76
|
-
return Command(
|
77
|
-
goto="s2_agent",
|
78
|
-
update={
|
79
|
-
"messages": state["messages"],
|
80
|
-
"is_last_step": False,
|
81
|
-
"current_agent": "s2_agent",
|
82
|
-
},
|
83
|
-
)
|
121
|
+
return Command(goto=goto)
|
84
122
|
|
85
123
|
return supervisor_node
|
86
124
|
|
87
125
|
|
88
|
-
def get_app(thread_id: str, llm_model="gpt-4o-mini") -> StateGraph:
|
126
|
+
def get_app(thread_id: str, llm_model: str = "gpt-4o-mini") -> StateGraph:
|
89
127
|
"""
|
90
|
-
|
128
|
+
Initializes and returns the LangGraph application with a hierarchical agent system.
|
129
|
+
|
130
|
+
This function sets up the full agent architecture, including the supervisor
|
131
|
+
and sub-agents, and compiles the LangGraph workflow for handling user queries.
|
91
132
|
|
92
133
|
Args:
|
93
|
-
thread_id (str):
|
134
|
+
thread_id (str): Unique identifier for the conversation session.
|
135
|
+
llm_model (str, optional): The language model to be used. Defaults to "gpt-4o-mini".
|
94
136
|
|
95
137
|
Returns:
|
96
|
-
|
97
|
-
"""
|
138
|
+
StateGraph: A compiled LangGraph application ready for query invocation.
|
98
139
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
)
|
105
|
-
cfg = cfg.agents.talk2scholars.main_agent
|
106
|
-
logger.info("Hydra configuration loaded with values: %s", cfg)
|
140
|
+
Example:
|
141
|
+
app = get_app("thread_123")
|
142
|
+
result = app.invoke(initial_state)
|
143
|
+
"""
|
144
|
+
cfg = get_hydra_config()
|
107
145
|
|
108
|
-
def call_s2_agent(
|
146
|
+
def call_s2_agent(
|
147
|
+
state: Talk2Scholars,
|
148
|
+
) -> Command[Literal["supervisor", "__end__"]]:
|
109
149
|
"""
|
110
|
-
|
150
|
+
Calls the Semantic Scholar (S2) agent to process academic paper queries.
|
151
|
+
|
152
|
+
This function invokes the S2 agent, retrieves relevant research papers,
|
153
|
+
and updates the conversation state accordingly.
|
111
154
|
|
112
155
|
Args:
|
113
|
-
state (Talk2Scholars): The current state
|
156
|
+
state (Talk2Scholars): The current conversation state, including user queries
|
157
|
+
and any previously retrieved papers.
|
114
158
|
|
115
159
|
Returns:
|
116
|
-
Command
|
160
|
+
Command: The next action to execute, along with updated messages and papers.
|
161
|
+
|
162
|
+
Example:
|
163
|
+
result = call_s2_agent(current_state)
|
164
|
+
next_step = result.goto
|
117
165
|
"""
|
118
166
|
logger.info("Calling S2 agent with state: %s", state)
|
119
167
|
app = s2_agent.get_app(thread_id, llm_model)
|
120
|
-
|
168
|
+
|
169
|
+
# Invoke the S2 agent, passing state,
|
170
|
+
# Pass both config_id and thread_id
|
171
|
+
response = app.invoke(
|
172
|
+
state,
|
173
|
+
{
|
174
|
+
"configurable": {
|
175
|
+
"config_id": thread_id,
|
176
|
+
"thread_id": thread_id,
|
177
|
+
}
|
178
|
+
},
|
179
|
+
)
|
121
180
|
logger.info("S2 agent completed with response: %s", response)
|
181
|
+
|
122
182
|
return Command(
|
123
183
|
goto=END,
|
124
184
|
update={
|
125
185
|
"messages": response["messages"],
|
126
|
-
"papers": response.get("papers",
|
127
|
-
"
|
128
|
-
"current_agent": "s2_agent",
|
186
|
+
"papers": response.get("papers", {}),
|
187
|
+
"multi_papers": response.get("multi_papers", {}),
|
129
188
|
},
|
130
189
|
)
|
131
190
|
|
132
|
-
|
133
|
-
|
134
|
-
"Using OpenAI model %s with temperature %s",
|
135
|
-
llm_model,
|
136
|
-
cfg.temperature
|
137
|
-
)
|
191
|
+
# Initialize LLM
|
192
|
+
logger.info("Using OpenAI model %s with temperature %s", llm_model, cfg.temperature)
|
138
193
|
llm = ChatOpenAI(model=llm_model, temperature=cfg.temperature)
|
194
|
+
|
195
|
+
# Build the graph
|
139
196
|
workflow = StateGraph(Talk2Scholars)
|
197
|
+
supervisor = make_supervisor_node(llm, thread_id)
|
140
198
|
|
141
|
-
supervisor = make_supervisor_node(llm, cfg)
|
142
199
|
workflow.add_node("supervisor", supervisor)
|
143
200
|
workflow.add_node("s2_agent", call_s2_agent)
|
144
|
-
|
145
|
-
# Define edges
|
146
201
|
workflow.add_edge(START, "supervisor")
|
147
202
|
workflow.add_edge("s2_agent", END)
|
148
203
|
|
204
|
+
# Compile the graph without initial state
|
149
205
|
app = workflow.compile(checkpointer=MemorySaver())
|
150
206
|
logger.info("Main agent workflow compiled")
|
151
207
|
return app
|
@@ -39,7 +39,7 @@ def get_app(uniq_id, llm_model="gpt-4o-mini"):
|
|
39
39
|
|
40
40
|
# Load hydra configuration
|
41
41
|
logger.log(logging.INFO, "Load Hydra configuration for Talk2Scholars S2 agent.")
|
42
|
-
with hydra.initialize(version_base=None, config_path="
|
42
|
+
with hydra.initialize(version_base=None, config_path="../configs"):
|
43
43
|
cfg = hydra.compose(
|
44
44
|
config_name="config", overrides=["agents/talk2scholars/s2_agent=default"]
|
45
45
|
)
|
@@ -57,6 +57,7 @@ def get_app(uniq_id, llm_model="gpt-4o-mini"):
|
|
57
57
|
llm,
|
58
58
|
tools=tools,
|
59
59
|
state_schema=Talk2Scholars,
|
60
|
+
# prompt=cfg.s2_agent,
|
60
61
|
state_modifier=cfg.s2_agent,
|
61
62
|
checkpointer=MemorySaver(),
|
62
63
|
)
|
@@ -6,34 +6,13 @@ openai_llms:
|
|
6
6
|
- "gpt-3.5-turbo"
|
7
7
|
temperature: 0
|
8
8
|
main_agent: >
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
"ALWAYS route to semantic_scholar_agent for:\n"
|
20
|
-
"- Finding academic papers\n"
|
21
|
-
"- Searching research topics\n"
|
22
|
-
"- Getting paper recommendations\n"
|
23
|
-
"- Finding similar papers\n"
|
24
|
-
"- Any query about academic literature\n\n"
|
25
|
-
"Approach:\n"
|
26
|
-
"1. Identify the core need in the user's query\n"
|
27
|
-
"2. Select the most appropriate tool based on the guidelines above\n"
|
28
|
-
"3. If unclear, ask for clarification\n"
|
29
|
-
"4. For multi-step tasks, focus on the immediate next step\n\n"
|
30
|
-
"Remember:\n"
|
31
|
-
"- Be decisive in your tool selection\n"
|
32
|
-
"- Focus on the immediate task\n"
|
33
|
-
"- Default to semantic_scholar_agent for any paper-finding tasks\n"
|
34
|
-
"- Ask for clarification if the request is ambiguous\n\n"
|
35
|
-
"When presenting paper search results, always use this exact format:\n\n"
|
36
|
-
"Remember to:\n"
|
37
|
-
"- To always add the url\n"
|
38
|
-
"- Put URLs on the title line itself as markdown\n"
|
39
|
-
"- Maintain consistent spacing and formatting"
|
9
|
+
You are an intelligent research assistant coordinating academic paper discovery and analysis.
|
10
|
+
|
11
|
+
AVAILABLE TOOLS AND ROUTING:
|
12
|
+
1. semantic_scholar_agent:
|
13
|
+
Access to tools:
|
14
|
+
- search_tool: For paper discovery
|
15
|
+
- display_results: For showing paper results
|
16
|
+
- get_single_paper_recommendations: For single paper recommendations
|
17
|
+
- get_multi_paper_recommendations: For multi-paper recommendations
|
18
|
+
→ ROUTE TO THIS AGENT FOR: Any query about academic papers, research, or articles
|
@@ -6,63 +6,19 @@ openai_llms:
|
|
6
6
|
- "gpt-3.5-turbo"
|
7
7
|
temperature: 0
|
8
8
|
s2_agent: >
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
"- Enhance search terms with academic language\n"
|
26
|
-
"- Include field-specific terminology\n"
|
27
|
-
'- Add "recent" or "latest" when appropriate\n'
|
28
|
-
"- Keep queries focused and relevant\n\n"
|
29
|
-
"For paper recommendations:\n"
|
30
|
-
"- Identify paper IDs (40-character hexadecimal strings)\n"
|
31
|
-
"- Use single_paper_recommendations for one ID\n"
|
32
|
-
"- Use multi_paper_recommendations for multiple IDs\n\n"
|
33
|
-
"Best practices:\n"
|
34
|
-
"1. Start with a broad search if no paper IDs are provided\n"
|
35
|
-
"2. Look for paper IDs in user input\n"
|
36
|
-
"3. Enhance search terms for better results\n"
|
37
|
-
"4. Consider the academic context\n"
|
38
|
-
"5. Be prepared to refine searches based on feedback\n\n"
|
39
|
-
"Remember:\n"
|
40
|
-
"- Always select the most appropriate tool\n"
|
41
|
-
"- Enhance search queries naturally\n"
|
42
|
-
"- Consider academic context\n"
|
43
|
-
"- Focus on delivering relevant results\n\n"
|
44
|
-
"IMPORTANT GUIDELINES FOR PAPER RECOMMENDATIONS:\n\n"
|
45
|
-
"For Multiple Papers:\n"
|
46
|
-
"- When getting recommendations for multiple papers, always use "
|
47
|
-
"get_multi_paper_recommendations tool\n"
|
48
|
-
"- DO NOT call get_single_paper_recommendations multiple times\n"
|
49
|
-
"- Always pass all paper IDs in a single call to get_multi_paper_recommendations\n"
|
50
|
-
'- Use for queries like "find papers related to both/all papers" or '
|
51
|
-
'"find similar papers to these papers"\n\n'
|
52
|
-
"For Single Paper:\n"
|
53
|
-
"- Use get_single_paper_recommendations when focusing on one specific paper\n"
|
54
|
-
"- Pass only one paper ID at a time\n"
|
55
|
-
'- Use for queries like "find papers similar to this paper" or '
|
56
|
-
'"get recommendations for paper X"\n'
|
57
|
-
"- Do not use for multiple papers\n\n"
|
58
|
-
"Examples:\n"
|
59
|
-
'- For "find related papers for both papers":\n'
|
60
|
-
" ✓ Use get_multi_paper_recommendations with both paper IDs\n"
|
61
|
-
" × Don't make multiple calls to get_single_paper_recommendations\n\n"
|
62
|
-
'- For "find papers related to the first paper":\n'
|
63
|
-
" ✓ Use get_single_paper_recommendations with just that paper's ID\n"
|
64
|
-
" × Don't use get_multi_paper_recommendations\n\n"
|
65
|
-
"Remember:\n"
|
66
|
-
"- Be precise in identifying which paper ID to use for single recommendations\n"
|
67
|
-
"- Don't reuse previous paper IDs unless specifically requested\n"
|
68
|
-
"- For fresh paper recommendations, always use the original paper ID"
|
9
|
+
You are a specialized academic research agent with access to tools for paper discovery and analysis.
|
10
|
+
|
11
|
+
YOUR TOOLS:
|
12
|
+
1. search_tool:
|
13
|
+
- Finds research papers based on user queries.
|
14
|
+
- If no papers are found, it performs a new search.
|
15
|
+
|
16
|
+
2. display_results:
|
17
|
+
- Shows the current research papers.
|
18
|
+
- If no papers are found, it will instruct you to perform a search.
|
19
|
+
|
20
|
+
3. get_single_paper_recommendations:
|
21
|
+
- Provides recommendations based on a single selected paper.
|
22
|
+
|
23
|
+
4. get_multi_paper_recommendations:
|
24
|
+
- Provides recommendations based on multiple selected papers.
|
@@ -3,10 +3,8 @@ This is the state file for the talk2scholars agent.
|
|
3
3
|
"""
|
4
4
|
|
5
5
|
import logging
|
6
|
-
from typing import Annotated, Any, Dict
|
7
|
-
|
6
|
+
from typing import Annotated, Any, Dict
|
8
7
|
from langgraph.prebuilt.chat_agent_executor import AgentState
|
9
|
-
from typing_extensions import NotRequired, Required
|
10
8
|
|
11
9
|
# Configure logging
|
12
10
|
logging.basicConfig(level=logging.INFO)
|
@@ -22,11 +20,14 @@ def replace_dict(existing: Dict[str, Any], new: Dict[str, Any]) -> Dict[str, Any
|
|
22
20
|
class Talk2Scholars(AgentState):
|
23
21
|
"""
|
24
22
|
The state for the talk2scholars agent, inheriting from AgentState.
|
23
|
+
|
24
|
+
Attributes:
|
25
|
+
papers: Dictionary of papers from search results
|
26
|
+
multi_papers: Dictionary of papers from multi-paper recommendations
|
27
|
+
llm_model: Model being used
|
25
28
|
"""
|
26
29
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
current_agent: NotRequired[Optional[str]]
|
31
|
-
is_last_step: Required[bool] # Required field for LangGraph
|
30
|
+
# Agent state fields
|
31
|
+
papers: Annotated[Dict[str, Any], replace_dict]
|
32
|
+
multi_papers: Annotated[Dict[str, Any], replace_dict]
|
32
33
|
llm_model: str
|