blob: e97b700eaa1bc24ecf31e18e817032065bebaf61 [file]
"""
Template for a multi-modal agent.
The idea is that this whole application functions as an agent that can do
multi-modal things.
Fill in the functions, and adjust/create new actions as needed.
"""
from typing import Tuple
from burr import tracking
from burr.core import Application, ApplicationBuilder, State, default, when
from burr.core.action import action
@action(reads=[], writes=["chat_history", "query"])
def apply_input_query(state: State, user_query: str) -> Tuple[dict, State]:
# this is a simple example of how you might process a user query -- stick it directly into the chat history
result = {"chat_item": {"role": "user", "content": user_query, "type": "text"}}
new_state = state.append(chat_history=result["chat_item"]).update(query=user_query)
return result, new_state
@action(reads=["prompt"], writes=["mode"])
def choose_mode(state: State) -> Tuple[dict, State]:
"""Code to choose a mode"""
result = {"mode": "example"}
return result, state.update(**result)
@action(reads=[], writes=["response"])
def unknown_action(state: State) -> Tuple[dict, State]:
result = {
"response": {
"content": "None of the response modes I support apply to your question. Please clarify?",
"type": "text",
"role": "assistant",
}
}
return result, state.update(**result)
@action(reads=["query", "chat_history", "mode"], writes=["response"])
def some_action(state: State) -> Tuple[dict, State]:
"""An example action -- create more of these to handle different modes"""
_query = state["query"] # noqa:F841
_mode = state["mode"] # noqa:F841
_chat_history = state["chat_history"] # noqa:F841
result = {"response": {"some": "response"}}
return result, state.update(**result)
@action(reads=["query", "mode", "response"], writes=["chat_history"])
def response(state: State) -> Tuple[dict, State]:
"""Function to create a response based on the prior action."""
_result = {
"content": state["response"],
"type": state["mode"],
"role": "assistant",
}
return _result, state.append(chat_history=_result)
def base_application(app_id: str, storage_dir: str, project_id: str) -> Application:
"""Creates the Burr application"""
tracker = tracking.LocalTrackingClient(project=project_id, storage_dir=storage_dir)
return (
ApplicationBuilder()
.with_actions(
apply_input_query=apply_input_query,
decide_mode=choose_mode,
unknown_action=unknown_action,
some_action=some_action,
response=response,
)
.with_transitions(
("apply_input_query", "decide_mode", default),
("decide_mode", "unknown_action", when(mode="unknown")),
("decide_mode", "some_action", when(mode="some_action")),
(["unknown_action", "some_action"], "response", default),
("response", "apply_input_query", default),
)
# initializes from the tracking log if it does not already exist
.initialize_from(
tracker,
resume_at_next_action=False, # always resume from entrypoint in the case of failure
default_state={"chat_history": []},
default_entrypoint="apply_input_query",
)
.with_tracker(tracker)
.with_identifiers(app_id=app_id)
.build()
)
if __name__ == "__main__":
import uuid
app_id: str = str(uuid.uuid4())
storage_dir: str = "~/.burr"
project_id: str = "template:multi-modal-agent"
app = base_application(app_id, storage_dir, project_id)
app.visualize(
output_file_path="multi_modal_agent", include_conditions=False, view=True, format="png"
)
# this is how you could run one cycle of the agent:
# app.run(halt_after=["response"], inputs={"user_query": "Hello, world!"})