-
Notifications
You must be signed in to change notification settings - Fork 915
/
Copy pathlangchain-agent.py
111 lines (85 loc) · 3.56 KB
/
langchain-agent.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
import asana
from asana.rest import ApiException
from openai import OpenAI
from dotenv import load_dotenv
from datetime import datetime
import json
import os
from langchain_core.tools import tool
from langchain_openai import ChatOpenAI
from langchain_anthropic import ChatAnthropic
from langchain_core.messages import SystemMessage, HumanMessage, ToolMessage
load_dotenv()
model = os.getenv('LLM_MODEL', 'gpt-4o')
configuration = asana.Configuration()
configuration.access_token = os.getenv('ASANA_ACCESS_TOKEN', '')
api_client = asana.ApiClient(configuration)
tasks_api_instance = asana.TasksApi(api_client)
@tool
def create_asana_task(task_name, due_on="today"):
"""
Creates a task in Asana given the name of the task and when it is due
Example call:
create_asana_task("Test Task", "2024-06-24")
Args:
task_name (str): The name of the task in Asana
due_on (str): The date the task is due in the format YYYY-MM-DD. If not given, the current day is used
Returns:
str: The API response of adding the task to Asana or an error message if the API call threw an error
"""
if due_on == "today":
due_on = str(datetime.now().date())
task_body = {
"data": {
"name": task_name,
"due_on": due_on,
"projects": [os.getenv("ASANA_PROJECT_ID", "")]
}
}
try:
api_response = tasks_api_instance.create_task(task_body, {})
return json.dumps(api_response, indent=2)
except ApiException as e:
return f"Exception when calling TasksApi->create_task: {e}"
def prompt_ai(messages, nested_calls=0):
if nested_calls > 5:
raise "AI is tool calling too much!"
# First, prompt the AI with the latest user message
tools = [create_asana_task]
asana_chatbot = ChatOpenAI(model=model) if "gpt" in model.lower() else ChatAnthropic(model=model)
asana_chatbot_with_tools = asana_chatbot.bind_tools(tools)
ai_response = asana_chatbot_with_tools.invoke(messages)
print(ai_response)
print(type(ai_response))
tool_calls = len(ai_response.tool_calls) > 0
# Second, see if the AI decided it needs to invoke a tool
if tool_calls:
# If the AI decided to invoke a tool, invoke it
available_functions = {
"create_asana_task": create_asana_task
}
# Add the tool request to the list of messages so the AI knows later it invoked the tool
messages.append(ai_response)
# Next, for each tool the AI wanted to call, call it and add the tool result to the list of messages
for tool_call in ai_response.tool_calls:
tool_name = tool_call["name"].lower()
selected_tool = available_functions[tool_name]
tool_output = selected_tool.invoke(tool_call["args"])
messages.append(ToolMessage(tool_output, tool_call_id=tool_call["id"]))
# Call the AI again so it can produce a response with the result of calling the tool(s)
ai_response = prompt_ai(messages, nested_calls + 1)
return ai_response
def main():
messages = [
SystemMessage(content=f"You are a personal assistant who helps manage tasks in Asana. The current date is: {datetime.now().date()}")
]
while True:
user_input = input("Chat with AI (q to quit): ").strip()
if user_input == 'q':
break
messages.append(HumanMessage(content=user_input))
ai_response = prompt_ai(messages)
print(ai_response.content)
messages.append(ai_response)
if __name__ == "__main__":
main()