Humanlearning commited on
Commit
df075f4
·
1 Parent(s): df804d4

first commit

Browse files
Files changed (8) hide show
  1. .gitignore +2 -0
  2. .python-version +1 -0
  3. agent.py +111 -0
  4. main.py +6 -0
  5. pyproject.toml +11 -0
  6. tools/__init__.py +0 -0
  7. tools/tavily_search_tool.py +34 -0
  8. uv.lock +0 -0
.gitignore ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ env*
2
+ .venv
.python-version ADDED
@@ -0,0 +1 @@
 
 
1
+ 3.13
agent.py ADDED
@@ -0,0 +1,111 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from llama_index.llms.openai import OpenAI
2
+ from tools.tavily_search_tool import search_web, record_notes, write_report, review_report
3
+ from dotenv import load_dotenv
4
+ import os
5
+ load_dotenv()
6
+
7
+ llm = OpenAI(model="gpt-4o", api_key=os.getenv("OPENAI_API_KEY"))
8
+
9
+ from llama_index.core.agent.workflow import FunctionAgent, ReActAgent
10
+
11
+ research_agent = FunctionAgent(
12
+ name="ResearchAgent",
13
+ description="Useful for searching the web for information on a given topic and recording notes on the topic.",
14
+ system_prompt=(
15
+ "You are the ResearchAgent that can search the web for information on a given topic and record notes on the topic. "
16
+ "Once notes are recorded and you are satisfied, you should hand off control to the WriteAgent to write a report on the topic. "
17
+ "You should have at least some notes on a topic before handing off control to the WriteAgent."
18
+ ),
19
+ llm=llm,
20
+ tools=[search_web, record_notes],
21
+ can_handoff_to=["WriteAgent"],
22
+ )
23
+
24
+ write_agent = FunctionAgent(
25
+ name="WriteAgent",
26
+ description="Useful for writing a report on a given topic.",
27
+ system_prompt=(
28
+ "You are the WriteAgent that can write a report on a given topic. "
29
+ "Your report should be in a markdown format. The content should be grounded in the research notes. "
30
+ "Once the report is written, you should get feedback at least once from the ReviewAgent."
31
+ ),
32
+ llm=llm,
33
+ tools=[write_report],
34
+ can_handoff_to=["ReviewAgent", "ResearchAgent"],
35
+ )
36
+
37
+ review_agent = FunctionAgent(
38
+ name="ReviewAgent",
39
+ description="Useful for reviewing a report and providing feedback.",
40
+ system_prompt=(
41
+ "You are the ReviewAgent that can review the write report and provide feedback. "
42
+ "Your review should either approve the current report or request changes for the WriteAgent to implement. "
43
+ "If you have feedback that requires changes, you should hand off control to the WriteAgent to implement the changes after submitting the review."
44
+ ),
45
+ llm=llm,
46
+ tools=[review_report],
47
+ can_handoff_to=["WriteAgent"],
48
+ )
49
+
50
+ from llama_index.core.agent.workflow import AgentWorkflow
51
+
52
+ agent_workflow = AgentWorkflow(
53
+ agents=[research_agent, write_agent, review_agent],
54
+ root_agent=research_agent.name,
55
+ initial_state={
56
+ "research_notes": {},
57
+ "report_content": "Not written yet.",
58
+ "review": "Review required.",
59
+ },
60
+ )
61
+
62
+
63
+ # As the workflow is running, we will stream the events to get an idea of what is happening under the hood.
64
+ from llama_index.core.agent.workflow import (
65
+ AgentInput,
66
+ AgentOutput,
67
+ ToolCall,
68
+ ToolCallResult,
69
+ AgentStream,
70
+ )
71
+
72
+ handler = agent_workflow.run(
73
+ user_msg=(
74
+ "Write me a report on the history of the internet. "
75
+ "Briefly describe the history of the internet, including the development of the internet, the development of the web, "
76
+ "and the development of the internet in the 21st century."
77
+ )
78
+ )
79
+
80
+ current_agent = None
81
+ current_tool_calls = ""
82
+ async for event in handler.stream_events():
83
+ if (
84
+ hasattr(event, "current_agent_name")
85
+ and event.current_agent_name != current_agent
86
+ ):
87
+ current_agent = event.current_agent_name
88
+ print(f"\n{'='*50}")
89
+ print(f"🤖 Agent: {current_agent}")
90
+ print(f"{'='*50}\n")
91
+
92
+ # if isinstance(event, AgentStream):
93
+ # if event.delta:
94
+ # print(event.delta, end="", flush=True)
95
+ # elif isinstance(event, AgentInput):
96
+ # print("📥 Input:", event.input)
97
+ elif isinstance(event, AgentOutput):
98
+ if event.response.content:
99
+ print("📤 Output:", event.response.content)
100
+ if event.tool_calls:
101
+ print(
102
+ "🛠️ Planning to use tools:",
103
+ [call.tool_name for call in event.tool_calls],
104
+ )
105
+ elif isinstance(event, ToolCallResult):
106
+ print(f"🔧 Tool Result ({event.tool_name}):")
107
+ print(f" Arguments: {event.tool_kwargs}")
108
+ print(f" Output: {event.tool_output}")
109
+ elif isinstance(event, ToolCall):
110
+ print(f"🔨 Calling Tool: {event.tool_name}")
111
+ print(f" With arguments: {event.tool_kwargs}")
main.py ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ def main():
2
+ print("Hello from teacher-student-agent!")
3
+
4
+
5
+ if __name__ == "__main__":
6
+ main()
pyproject.toml ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [project]
2
+ name = "teacher-student-agent"
3
+ version = "0.1.0"
4
+ description = "Add your description here"
5
+ readme = "README.md"
6
+ requires-python = ">=3.13"
7
+ dependencies = [
8
+ "dotenv>=0.9.9",
9
+ "llama-index>=0.12.40",
10
+ "tavily-python>=0.7.5",
11
+ ]
tools/__init__.py ADDED
File without changes
tools/tavily_search_tool.py ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from tavily import AsyncTavilyClient
2
+ from llama_index.core.workflow import Context
3
+
4
+
5
+ async def search_web(query: str) -> str:
6
+ """Useful for using the web to answer questions."""
7
+ client = AsyncTavilyClient(api_key="tvly-...")
8
+ return str(await client.search(query))
9
+
10
+
11
+ async def record_notes(ctx: Context, notes: str, notes_title: str) -> str:
12
+ """Useful for recording notes on a given topic. Your input should be notes with a title to save the notes under."""
13
+ current_state = await ctx.get("state")
14
+ if "research_notes" not in current_state:
15
+ current_state["research_notes"] = {}
16
+ current_state["research_notes"][notes_title] = notes
17
+ await ctx.set("state", current_state)
18
+ return "Notes recorded."
19
+
20
+
21
+ async def write_report(ctx: Context, report_content: str) -> str:
22
+ """Useful for writing a report on a given topic. Your input should be a markdown formatted report."""
23
+ current_state = await ctx.get("state")
24
+ current_state["report_content"] = report_content
25
+ await ctx.set("state", current_state)
26
+ return "Report written."
27
+
28
+
29
+ async def review_report(ctx: Context, review: str) -> str:
30
+ """Useful for reviewing a report and providing feedback. Your input should be a review of the report."""
31
+ current_state = await ctx.get("state")
32
+ current_state["review"] = review
33
+ await ctx.set("state", current_state)
34
+ return "Report reviewed."
uv.lock ADDED
The diff for this file is too large to render. See raw diff