-
-
Notifications
You must be signed in to change notification settings - Fork 171
/
chat-tree.py
234 lines (191 loc) · 6.71 KB
/
chat-tree.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
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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
"""
Simple example showing tree-structured computation
where each node in the tree is handled by a separate agent.
This task consists of performing this calculation for a given input number n:
def Main(n):
if n is odd:
return (3*n+1) + n
else:
If n is divisible by 10:
return n/10 + n
else:
return n/2 + n
To make this "interesting", we represent this computation hierarchically,
in the form of this tree:
Main
- Odd
- Adder
- Even
- EvenZ
- Adder
- EvenNZ
- Adder
For a full write-up on the design considerations, see the documentation page on
Hiearchical Agent Computations at https://langroid.github.io/langroid/examples/agent-tree/
"""
import typer
from rich.prompt import Prompt
from langroid.agent.chat_agent import ChatAgent, ChatAgentConfig
from langroid.agent.task import Task
from langroid.agent.tool_message import ToolMessage
from langroid.language_models.openai_gpt import OpenAIChatModel, OpenAIGPTConfig
from langroid.utils.globals import GlobalState
from langroid.utils.configuration import set_global, Settings
from langroid.utils.logging import setup_colored_logging
from langroid.utils.constants import DONE
app = typer.Typer()
setup_colored_logging()
class MyGlobalState(GlobalState):
number: int | None = None
class AskNumTool(ToolMessage):
request = "ask_num"
purpose = "Ask user for the initial number"
def handle(self) -> str:
"""
This is a stateless tool (i.e. does not use any Agent member vars), so we can
define the handler right here, instead of defining an `ask_num`
method in the agent.
"""
num = Prompt.ask("Enter a number")
# record this in global state, so other agents can access it
MyGlobalState.set_values(number=num)
return str(num)
class AddNumTool(ToolMessage):
request = "add_num"
purpose = "Add <number> to the original number, return the result"
number: int
def handle(self) -> str:
"""
This is a stateless tool (i.e. does not use any Agent member vars), so we can
define the handler right here, instead of defining an `add_num`
method in the agent.
"""
return str(int(MyGlobalState.get_value("number")) + int(self.number))
def chat() -> None:
config = ChatAgentConfig(
llm=OpenAIGPTConfig(
chat_model=OpenAIChatModel.GPT4,
),
vecdb=None,
)
main_agent = ChatAgent(config)
main_task = Task(
main_agent,
name="Main",
interactive=False,
system_message="""
You will receive two types of messages, to which you will respond as follows:
INPUT Message format: <number>
In this case simply write the <number>, say nothing else.
RESULT Message format: RESULT <number>
In this case simply say "DONE <number>", e.g.:
DONE 19
To start off, ask the user for the initial number,
using the `ask_num` tool/function.
""",
)
# Handles only even numbers
even_agent = ChatAgent(config)
even_task = Task(
even_agent,
name="Even",
interactive=False,
system_message=f"""
You will receive two types of messages, to which you will respond as follows:
INPUT Message format: <number>
- if the <number> is odd, say '{DONE}'
- otherwise, simply write the <number>, say nothing else.
RESULT Message format: RESULT <number>
In this case simply write "DONE RESULT <number>", e.g.:
DONE RESULT 19
""",
)
# handles only even numbers ending in Zero
evenz_agent = ChatAgent(config)
evenz_task = Task(
evenz_agent,
name="EvenZ",
interactive=False,
system_message=f"""
You will receive two types of messages, to which you will respond as follows:
INPUT Message format: <number>
- if <number> n is even AND divisible by 10, compute n/10 and pass it on,
- otherwise, say '{DONE}'
RESULT Message format: RESULT <number>
In this case simply write "DONE RESULT <number>", e.g.:
DONE RESULT 19
""",
)
# Handles only even numbers NOT ending in Zero
even_nz_agent = ChatAgent(config)
even_nz_task = Task(
even_nz_agent,
name="EvenNZ",
interactive=False,
system_message=f"""
You will receive two types of messages, to which you will respond as follows:
INPUT Message format: <number>
- if <number> n is even AND NOT divisible by 10, compute n/2 and pass it on,
- otherwise, say '{DONE}'
RESULT Message format: RESULT <number>
In this case simply write "DONE RESULT <number>", e.g.:
DONE RESULT 19
""",
)
# Handles only odd numbers
odd_agent = ChatAgent(config)
odd_task = Task(
odd_agent,
name="Odd",
interactive=False,
system_message=f"""
You will receive two types of messages, to which you will respond as follows:
INPUT Message format: <number>
- if <number> n is odd, compute n*3+1 and write it.
- otherwise, say '{DONE}'
RESULT Message format: RESULT <number>
In this case simply write "DONE RESULT <number>", e.g.:
DONE RESULT 19
""",
)
adder_agent = ChatAgent(config)
adder_task = Task(
adder_agent,
name="Adder",
interactive=False,
system_message="""
You will be given a number n.
You have to add it to the original number and return the result.
You do not know the original number, so you must use the
`add_num` tool/function for this.
When you receive the result, say "DONE RESULT <result>", e.g.
DONE RESULT 19
""",
)
# set up tasks and subtasks
main_task.add_sub_task([even_task, odd_task])
even_task.add_sub_task([evenz_task, even_nz_task])
evenz_task.add_sub_task(adder_task)
even_nz_task.add_sub_task(adder_task)
odd_task.add_sub_task(adder_task)
# set up the tools
main_agent.enable_message(AskNumTool)
adder_agent.enable_message(AddNumTool)
# start the chat
main_task.run()
@app.command()
def main(
debug: bool = typer.Option(False, "--debug", "-d", help="debug mode"),
no_stream: bool = typer.Option(False, "--nostream", "-ns", help="no streaming"),
nocache: bool = typer.Option(False, "--nocache", "-nc", help="don't use cache"),
) -> None:
set_global(
Settings(
debug=debug,
cache=not nocache,
stream=not no_stream,
)
)
chat()
if __name__ == "__main__":
app()