File size: 10,342 Bytes
3943768
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import os
import tempfile

from autogen.agentchat import gather_usage_summary

from openai_server.backend_utils import structure_to_messages
from openai_server.agent_utils import get_ret_dict_and_handle_files
from openai_server.agent_prompting import get_full_system_prompt

from openai_server.autogen_utils import merge_group_chat_messages
from openai_server.autogen_utils import get_all_conversable_agents


def run_autogen_multi_agent(query=None,
                            visible_models=None,
                            stream_output=None,
                            max_new_tokens=None,
                            authorization=None,
                            chat_conversation=None,
                            text_context_list=None,
                            system_prompt=None,
                            image_file=None,
                            # autogen/agent specific parameters
                            agent_type=None,
                            agent_accuracy=None,
                            agent_chat_history=None,
                            agent_files=None,
                            autogen_stop_docker_executor=None,
                            autogen_run_code_in_docker=None,
                            autogen_max_consecutive_auto_reply=None,
                            autogen_max_turns=None,
                            autogen_timeout=None,
                            autogen_cache_seed=None,
                            agent_venv_dir=None,
                            agent_code_writer_system_message=None,
                            agent_system_site_packages=None,
                            autogen_code_restrictions_level=None,
                            autogen_silent_exchange=None,
                            agent_verbose=None) -> dict:
    assert agent_type in ['autogen_multi_agent'], "Invalid agent_type: %s" % agent_type
    # raise openai.BadRequestError("Testing Error Handling")
    # raise ValueError("Testing Error Handling")

    # handle parameters from chatAPI and OpenAI -> h2oGPT transcription versions
    assert visible_models is not None, "No visible_models specified"
    model = visible_models  # transcribe early

    if stream_output is None:
        stream_output = False
    assert max_new_tokens is not None, "No max_new_tokens specified"

    # handle AutoGen specific parameters
    if autogen_stop_docker_executor is None:
        autogen_stop_docker_executor = False
    if autogen_run_code_in_docker is None:
        autogen_run_code_in_docker = False
    if autogen_max_consecutive_auto_reply is None:
        autogen_max_consecutive_auto_reply = 40
    if autogen_max_turns is None:
        autogen_max_turns = 40
    if autogen_timeout is None:
        autogen_timeout = 120
    if agent_system_site_packages is None:
        agent_system_site_packages = True
    if autogen_code_restrictions_level is None:
        autogen_code_restrictions_level = 2
    if autogen_silent_exchange is None:
        autogen_silent_exchange = True
    if agent_verbose is None:
        agent_verbose = False
    if agent_verbose:
        print("AutoGen using model=%s." % model, flush=True)

    base_url = os.environ['H2OGPT_OPENAI_BASE_URL']  # must exist
    api_key = os.environ['H2OGPT_OPENAI_API_KEY']  # must exist
    agent_work_dir = tempfile.mkdtemp()
    from openai_server.autogen_utils import get_code_executor
    from openai_server.autogen_agents import (
        get_human_proxy_agent,
        get_main_group_chat_manager,
        get_chat_agent,
        get_code_group_chat_manager
    )

    # Create a code executor.
    executor = get_code_executor(
        autogen_run_code_in_docker=autogen_run_code_in_docker,
        autogen_timeout=autogen_timeout,
        agent_system_site_packages=agent_system_site_packages,
        autogen_code_restrictions_level=autogen_code_restrictions_level,
        agent_work_dir=agent_work_dir,
        agent_venv_dir=agent_venv_dir,
    )

    # Prepare the system message for the code writer agent.
    code_writer_system_prompt, internal_file_names, system_message_parts = \
        get_full_system_prompt(agent_code_writer_system_message,
                               agent_system_site_packages, system_prompt,
                               base_url,
                               api_key, model, text_context_list, image_file,
                               agent_work_dir, query, autogen_timeout)
    # Prepare the LLM config for the agents
    extra_body = {
        "agent_type": agent_type,  # autogen_multi_agent
    }
    llm_config = {"config_list": [{"model": model,
                                   "api_key": api_key,
                                   "base_url": base_url,
                                   "stream": stream_output,
                                   "cache_seed": autogen_cache_seed,
                                   'max_tokens': max_new_tokens,
                                   "extra_body": extra_body,
                                   }]}
    human_proxy_agent = get_human_proxy_agent(
        llm_config=llm_config,
        autogen_max_consecutive_auto_reply=autogen_max_consecutive_auto_reply,

    )
    chat_agent = get_chat_agent(
        llm_config=llm_config,
        autogen_max_consecutive_auto_reply=1,  # Always 1 turn for chat agent
    )
    code_group_chat_manager = get_code_group_chat_manager(
        llm_config=llm_config,
        code_writer_system_prompt=code_writer_system_prompt,
        autogen_max_consecutive_auto_reply=autogen_max_consecutive_auto_reply,
        max_round=40,  # TODO: Define variable above
        executor=executor,
    )
    main_group_chat_manager = get_main_group_chat_manager(
        llm_config=llm_config,
        prompt=query,
        agents=[chat_agent, code_group_chat_manager],
        max_round=40,
    )
    # apply chat history to human_proxy_agent and main_group_chat_manager
    # TODO: check if working
    if chat_conversation:
        chat_messages = structure_to_messages(None, None, chat_conversation, None)
        for message in chat_messages:
            if message['role'] == 'assistant':
                main_group_chat_manager.send(message['content'], human_proxy_agent, request_reply=False)
            if message['role'] == 'user':
                human_proxy_agent.send(message['content'], main_group_chat_manager, request_reply=False)

    chat_result = human_proxy_agent.initiate_chat(
        main_group_chat_manager,
        message=query,
        # summary_method="last_msg", # TODO: is summary really working for group chat? Doesnt include code group messages in it, why?
        # summary_args=dict(summary_role="user"), # System by default, but in chat histort it comes last and drops user message in h2ogpt/convert_messages_to_structure method
        max_turns=1,
    )
    # It seems chat_result.chat_history doesnt contain code group messages, so I'm manually merging them here. #TODO: research why so?
    merged_group_chat_messages = merge_group_chat_messages(
        code_group_chat_manager.groupchat.messages, main_group_chat_manager.groupchat.messages
    )
    chat_result.chat_history = merged_group_chat_messages
    # Update summary after including group chats:
    used_agents = list(set([msg['name'] for msg in chat_result.chat_history]))
    # besides human_proxy_agent, check if there is only chat_agent and human_proxy_agent in the used_agents
    if len(used_agents) == 2 and 'chat_agent' in used_agents:
        # If it's only chat_agent and human_proxy_agent, then use last message as summary
        summary = chat_result.chat_history[-1]['content']
    else:
        summarize_prompt = (
            "* Given all the conversation and findings so far, try to answer first user instruction. "
            "* Do not add any introductory phrases. "
            "* After answering user instruction, now you can try to summarize the process. "
            "* In your final summarization, if any key figures or plots were produced, "
            "add inline markdown links to the files so they are rendered as images in the chat history. "
            "Do not include them in code blocks, just directly inlined markdown like ![image](filename.png). "
            "Only use the basename of the file, not the full path, "
            "and the user will map the basename to a local copy of the file so rendering works normally. "
            "* If you have already displayed some images in your answer to the user, you don't need to add them again in the summary. "
            "* Do not try to answer the instruction yourself, just answer based on what is in chat history. "
        )
        summary_chat_history = [msg for msg in chat_result.chat_history]
        for msg in summary_chat_history:
            if msg['name'] == 'human_proxy_agent':
                msg['role'] = 'user'
            else:
                msg['role'] = 'assistant'

        summary = human_proxy_agent._reflection_with_llm(
            prompt=summarize_prompt,
            messages=chat_result.chat_history,
            cache=None,
            role="user"
        )

    # A little sumamry clean-up
    summary = summary.replace("ENDOFTURN", " ").replace("<FINISHED_ALL_TASKS>", " ")
    # Update chat_result with summary
    chat_result.summary = summary
    # Update final usage cost
    all_conversable_agents = [human_proxy_agent] + get_all_conversable_agents(main_group_chat_manager)
    chat_result.cost = gather_usage_summary(all_conversable_agents)
    #### end
    ret_dict = get_ret_dict_and_handle_files(chat_result,
                                             None,
                                             model,
                                             agent_work_dir, agent_verbose, internal_file_names, authorization,
                                             autogen_run_code_in_docker, autogen_stop_docker_executor, executor,
                                             agent_venv_dir, agent_code_writer_system_message,
                                             agent_system_site_packages,
                                             system_message_parts,
                                             autogen_code_restrictions_level, autogen_silent_exchange,
                                             agent_accuracy)

    return ret_dict