Open skrawcz opened 6 months ago
Hi, thank you for the very nice framework you are developing! I am considering uplifting my LLM workflow with burr. Right now, I am trying to figure out how to implement an action that asks for human inputs iteratively. One of the examples shows that I can build an application with a human input action, then I can hault before the action and provide human inputs in a for/while loop. But how do I wrap this for/while input loop into an action so that I can orchestrate it with other actions? This issue seems to be relevant to my question, so I am posting here for your guidance. Thank you!
Posting this from my response in discord:
Yeah so burr is pretty flexible with how you walk / iterate through a burr application (i.e. graph). In this application from https://github.com/DAGWorks-Inc/burr/tree/main/examples/email-assistant. You could do this if you're running it from the command line
inputs = {"email_to_respond": ..., "response_instructions": ...}
while True:
_action, _result, _state = my_app.run(halt_before=["clarify_instructions", "process_feedback"], inputs=inputs)
if _action.name == "clarify_instructions":
# get inputs for that
inputs = {"clarification_inputs": ...} # could use `inputs("please clarify:")
elif _action.name == "process_feedback":
# ...
inputs = ...
elif _action.name == "final_result"
break
This will run the other actions, but stop before the ones that need input.
If so, can I halt before an action of a sub application to provide input/augment the state? Now with sub-applications within an action -- that is a little more involved if you want to provide inputs like in the above way. The wrapping action would need a self-loop until the sub-application completed, so basically you'd have:
@action(...)
def my_action(state: State, user_input: str) -> ...:
sub_application = ...
input_for_action = ... # get that from state/ user_input
while True:
_action, _result, _state = sub_application.run(halt_before=["some_user_input"], inputs=input_for_action)
if _action.name == "some_user_input":
new_state = state.update(need_input=True)
return new_state
if _action.name == "some_terminal_action":
new_state = state.update(need_input=False)
... # do other things
return new_state
and you'd have your application then have a conditional transition back to itself based on whether need_input was required.
Now since you're doing a command line, you could "cheat" a little, because you can stick input("...")
anywhere really -- and skip having to manage this control flow explicitly to get user input.
Otherwise for a simple example (without the nested sub-application) of using inputs(...)
see the GraphDB RAG application - https://github.com/DAGWorks-Inc/burr/blob/main/examples/conversational-rag/graph_db_example/application.py#L247-L254
If someone is building an agent, an agent can go do stuff, but then might need help.
Frame that example using
run(halt_before=["human_step"])
...TODO: