Agents

In UFO, there are four types of agents: HostAgent, AppAgent, FollowerAgent, and EvaluationAgent. Each agent has a specific role in the UFO system and is responsible for different aspects of the user interaction process:

Agent Description
HostAgent Decomposes the user request into sub-tasks and selects the appropriate application to fulfill the request.
AppAgent Executes actions on the selected application.
FollowerAgent Follows the user's instructions to complete the task.
EvaluationAgent Evaluates the completeness of a session or a round.

In the normal workflow, only the HostAgent and AppAgent are involved in the user interaction process. The FollowerAgent and EvaluationAgent are used for specific tasks.

Please see below the orchestration of the agents in UFO:

Main Components

An agent in UFO is composed of the following main components to fulfill its role in the UFO system:

Component Description
State Represents the current state of the agent and determines the next action and agent to handle the request.
Memory Stores information about the user request, application state, and other relevant data.
Blackboard Stores information shared between agents.
Prompter Generates prompts for the language model based on the user request and application state.
Processor Processes the workflow of the agent, including handling user requests, executing actions, and memory management.

Reference

Below is the reference for the Agent class in UFO. All agents in UFO inherit from the Agent class and implement necessary methods to fulfill their roles in the UFO system.

Bases: ABC

The BasicAgent class is the abstract class for the agent.

Initialize the BasicAgent.

Parameters:
  • name (str) –

    The name of the agent.

Source code in agents/agent/basic.py
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
def __init__(self, name: str) -> None:
    """
    Initialize the BasicAgent.
    :param name: The name of the agent.
    """
    self._step = 0
    self._complete = False
    self._name = name
    self._status = self.status_manager.CONTINUE.value
    self._register_self()
    self.retriever_factory = retriever.RetrieverFactory()
    self._memory = Memory()
    self._host = None
    self._processor: Optional[BaseProcessor] = None
    self._state = None

blackboard: Blackboard property

Get the blackboard.

Returns:
  • Blackboard

    The blackboard.

host: HostAgent property writable

Get the host of the agent.

Returns:
  • HostAgent

    The host of the agent.

memory: Memory property

Get the memory of the agent.

Returns:
  • Memory

    The memory of the agent.

name: str property

Get the name of the agent.

Returns:
  • str

    The name of the agent.

processor: BaseProcessor property writable

Get the processor.

Returns:
  • BaseProcessor

    The processor.

state: AgentState property

Get the state of the agent.

Returns:
  • AgentState

    The state of the agent.

status: str property writable

Get the status of the agent.

Returns:
  • str

    The status of the agent.

status_manager: AgentStatus property

Get the status manager.

Returns:
  • AgentStatus

    The status manager.

step: int property writable

Get the step of the agent.

Returns:
  • int

    The step of the agent.

add_memory(memory_item)

Update the memory of the agent.

Parameters:
  • memory_item (MemoryItem) –

    The memory item to add.

Source code in agents/agent/basic.py
180
181
182
183
184
185
def add_memory(self, memory_item: MemoryItem) -> None:
    """
    Update the memory of the agent.
    :param memory_item: The memory item to add.
    """
    self._memory.add_memory_item(memory_item)

build_experience_retriever()

Build the experience retriever.

Source code in agents/agent/basic.py
315
316
317
318
319
def build_experience_retriever(self) -> None:
    """
    Build the experience retriever.
    """
    pass

build_human_demonstration_retriever()

Build the human demonstration retriever.

Source code in agents/agent/basic.py
321
322
323
324
325
def build_human_demonstration_retriever(self) -> None:
    """
    Build the human demonstration retriever.
    """
    pass

build_offline_docs_retriever()

Build the offline docs retriever.

Source code in agents/agent/basic.py
303
304
305
306
307
def build_offline_docs_retriever(self) -> None:
    """
    Build the offline docs retriever.
    """
    pass

build_online_search_retriever()

Build the online search retriever.

Source code in agents/agent/basic.py
309
310
311
312
313
def build_online_search_retriever(self) -> None:
    """
    Build the online search retriever.
    """
    pass

clear_memory()

Clear the memory of the agent.

Source code in agents/agent/basic.py
194
195
196
197
198
def clear_memory(self) -> None:
    """
    Clear the memory of the agent.
    """
    self._memory.clear()

create_puppteer_interface()

Create the puppeteer interface.

Source code in agents/agent/basic.py
101
102
103
104
105
def create_puppteer_interface(self) -> puppeteer.AppPuppeteer:
    """
    Create the puppeteer interface.
    """
    pass

delete_memory(step)

Delete the memory of the agent.

Parameters:
  • step (int) –

    The step of the memory item to delete.

Source code in agents/agent/basic.py
187
188
189
190
191
192
def delete_memory(self, step: int) -> None:
    """
    Delete the memory of the agent.
    :param step: The step of the memory item to delete.
    """
    self._memory.delete_memory_item(step)

get_cls(name) classmethod

Retrieves an agent class from the registry.

Parameters:
  • name (str) –

    The name of the agent class.

Returns:
  • Type['BasicAgent']

    The agent class.

Source code in agents/agent/basic.py
342
343
344
345
346
347
348
349
@classmethod
def get_cls(cls, name: str) -> Type["BasicAgent"]:
    """
    Retrieves an agent class from the registry.
    :param name: The name of the agent class.
    :return: The agent class.
    """
    return AgentRegistry().get_cls(name)

get_prompter() abstractmethod

Get the prompt for the agent.

Returns:
  • str

    The prompt.

Source code in agents/agent/basic.py
123
124
125
126
127
128
129
@abstractmethod
def get_prompter(self) -> str:
    """
    Get the prompt for the agent.
    :return: The prompt.
    """
    pass

get_response(message, namescope, use_backup_engine) classmethod

Get the response for the prompt.

Parameters:
  • message (List[dict]) –

    The message for LLMs.

  • namescope (str) –

    The namescope for the LLMs.

  • use_backup_engine (bool) –

    Whether to use the backup engine.

Returns:
  • str

    The response.

Source code in agents/agent/basic.py
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
@classmethod
def get_response(
    cls, message: List[dict], namescope: str, use_backup_engine: bool
) -> str:
    """
    Get the response for the prompt.
    :param message: The message for LLMs.
    :param namescope: The namescope for the LLMs.
    :param use_backup_engine: Whether to use the backup engine.
    :return: The response.
    """
    response_string, cost = llm_call.get_completion(
        message, namescope, use_backup_engine=use_backup_engine
    )
    return response_string, cost

handle(context)

Handle the agent.

Parameters:
  • context (Context) –

    The context for the agent.

Source code in agents/agent/basic.py
219
220
221
222
223
224
def handle(self, context: Context) -> None:
    """
    Handle the agent.
    :param context: The context for the agent.
    """
    self.state.handle(self, context)

message_constructor() abstractmethod

Construct the message.

Returns:
  • List[Dict[str, Union[str, List[Dict[str, str]]]]]

    The message.

Source code in agents/agent/basic.py
131
132
133
134
135
136
137
@abstractmethod
def message_constructor(self) -> List[Dict[str, Union[str, List[Dict[str, str]]]]]:
    """
    Construct the message.
    :return: The message.
    """
    pass

print_response()

Print the response.

Source code in agents/agent/basic.py
327
328
329
330
331
def print_response(self) -> None:
    """
    Print the response.
    """
    pass

process(context)

Process the agent.

Source code in agents/agent/basic.py
226
227
228
229
230
def process(self, context: Context) -> None:
    """
    Process the agent.
    """
    pass

process_asker(ask_user=True)

Ask for the process.

Parameters:
  • ask_user (bool, default: True ) –

    Whether to ask the user for the questions.

Source code in agents/agent/basic.py
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
def process_asker(self, ask_user: bool = True) -> None:
    """
    Ask for the process.
    :param ask_user: Whether to ask the user for the questions.
    """
    if self.processor:
        question_list = self.processor.question_list

        if ask_user:
            utils.print_with_color(
                "Could you please answer the following questions to help me understand your needs and complete the task?",
                "yellow",
            )

        for index, question in enumerate(question_list):
            if ask_user:
                answer = question_asker(question, index + 1)
                if not answer.strip():
                    continue
                qa_pair = {"question": question, "answer": answer}

                utils.append_string_to_file(
                    configs["QA_PAIR_FILE"], json.dumps(qa_pair)
                )

            else:
                qa_pair = {
                    "question": question,
                    "answer": "The answer for the question is not available, please proceed with your own knowledge or experience, or leave it as a placeholder. Do not ask the same question again.",
                }

            self.blackboard.add_questions(qa_pair)

process_comfirmation() abstractmethod

Confirm the process.

Source code in agents/agent/basic.py
272
273
274
275
276
277
@abstractmethod
def process_comfirmation(self) -> None:
    """
    Confirm the process.
    """
    pass

process_resume()

Resume the process.

Source code in agents/agent/basic.py
232
233
234
235
236
237
def process_resume(self) -> None:
    """
    Resume the process.
    """
    if self.processor:
        self.processor.resume()

reflection()

TODO: Reflect on the action.

Source code in agents/agent/basic.py
200
201
202
203
204
205
def reflection(self) -> None:
    """
    TODO:
    Reflect on the action.
    """
    pass

response_to_dict(response) staticmethod

Convert the response to a dictionary.

Parameters:
  • response (str) –

    The response.

Returns:
  • Dict[str, str]

    The dictionary.

Source code in agents/agent/basic.py
155
156
157
158
159
160
161
162
@staticmethod
def response_to_dict(response: str) -> Dict[str, str]:
    """
    Convert the response to a dictionary.
    :param response: The response.
    :return: The dictionary.
    """
    return utils.json_parser(response)

set_state(state)

Set the state of the agent.

Parameters:
  • state (AgentState) –

    The state of the agent.

Source code in agents/agent/basic.py
207
208
209
210
211
212
213
214
215
216
217
def set_state(self, state: AgentState) -> None:
    """
    Set the state of the agent.
    :param state: The state of the agent.
    """

    assert issubclass(
        type(self), state.agent_class()
    ), f"The state is only for agent type of {state.agent_class()}, but the current agent is {type(self)}."

    self._state = state