forked from CopilotKit/CopilotKit
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathagent.py
More file actions
142 lines (117 loc) · 4.58 KB
/
Copy pathagent.py
File metadata and controls
142 lines (117 loc) · 4.58 KB
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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
"""
This is the main entry point for the agent.
It defines the workflow graph, state, tools, nodes and edges.
"""
import json
from ag_ui_crewai.sdk import CopilotKitState, copilotkit_stream
from crewai.flow.flow import Flow, listen, router, start
from litellm import completion
class AgentState(CopilotKitState):
"""
Here we define the state of the agent
In this instance, we're inheriting from CopilotKitState, which will bring in
the CopilotKitState fields. We're also adding a custom field, `language`,
which will be used to set the language of the agent.
"""
proverbs: list[str] = []
# your_custom_agent_state: str = ""
GET_WEATHER_TOOL = {
"type": "function",
"function": {
"name": "get_weather",
"description": "Get the current weather in a given location",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "The city and state, e.g. San Francisco, CA",
}
},
"required": ["location"],
},
},
}
tools = [
GET_WEATHER_TOOL
# your_tool_here
]
tool_handlers = {
"get_weather": lambda args: (
f"The weather for {args['location']} is 70 degrees, clear skies, 45% humidity, 5 mph wind, and feels like 72 degrees."
)
# your tool handler here
}
class SampleAgentFlow(Flow[AgentState]):
"""
This is a sample flow that uses the CopilotKit framework to create a chat agent.
"""
@start()
@listen("route_follow_up")
async def start_flow(self):
"""
This is the entry point for the flow.
"""
@router(start_flow)
async def chat(self):
"""
Standard chat node based on the ReAct design pattern. It handles:
- The model to use (and binds in CopilotKit actions and the tools defined above)
- The system prompt
- Getting a response from the model
- Handling tool calls
For more about the ReAct design pattern, see:
https://www.perplexity.ai/search/react-agents-NcXLQhreS0WDzpVaS4m9Cg
"""
system_prompt = f"You are a helpful assistant. The current proverbs are {self.state.proverbs}."
# 1. Run the model and stream the response
# Note: In order to stream the response, wrap the completion call in
# copilotkit_stream and set stream=True.
response = await copilotkit_stream(
completion(
# 1.1 Specify the model to use
model="openai/gpt-4o",
messages=[
{"role": "system", "content": system_prompt},
*self.state.messages,
],
# 1.2 Bind the tools to the model
tools=[*self.state.copilotkit.actions, GET_WEATHER_TOOL],
# 1.3 Disable parallel tool calls to avoid race conditions,
# enable this for faster performance if you want to manage
# the complexity of running tool calls in parallel.
parallel_tool_calls=False,
stream=True,
)
)
message = response.choices[0].message
# 2. Append the message to the messages in state
self.state.messages.append(message)
# 3. Handle tool calls
if message.get("tool_calls"):
tool_call = message["tool_calls"][0]
tool_call_id = tool_call["id"]
tool_call_name = tool_call["function"]["name"]
tool_call_args = json.loads(tool_call["function"]["arguments"])
# 4. Check for tool calls in the response and handle them. If the tool call
# is a CopilotKit action, we return the response to CopilotKit to handle
if tool_call_name in [
action["function"]["name"] for action in self.state.copilotkit.actions
]:
return "route_end"
# 5. Otherwise, we handle the tool call on the backend
handler = tool_handlers[tool_call_name]
result = handler(tool_call_args)
# 6. Append the result to the messages in state
self.state.messages.append(
{"role": "tool", "content": result, "tool_call_id": tool_call_id}
)
# 7. Return to the follow up route to continue the conversation
return "route_follow_up"
# 8. If there are no tool calls, return to the end route
return "route_end"
@listen("route_end")
async def end(self):
"""
End the flow.
"""