burr icon indicating copy to clipboard operation
burr copied to clipboard

Allow actions to not specify intermediate result

Open elijahbenizzy opened this issue 1 year ago • 2 comments

Take the following:

@action(reads=['input_var'], writes=['output_var'])
def simple_action(state: State) -> tuple[dict, State]:
    output_var = _compute(state["input_var"])
    result = {"output_var" : output_var}
    return result, state.update(**result)
    # or 
    return result, state.append(**result)

This is just a lot of boiler plate -- you have to:

  1. Compute the result
  2. Store it in a variable
  3. return it
  4. Apply a state update using it

Note most people will probably write it like this:

@action(reads=['input_var'], writes=['output_var', 'output_var_list'])
def simple_action(state: State) -> tuple[dict, State]:
    output_var = _compute(state["input_var"])
    return {"output_var" : output_var}, state.update(output_var=output_var).append(output_var_list=output_var)

Which is correct, but kind of strange. This is due to the oddity of the "single-step" action. That said, if we want these as simple python functions, then we don't really need the result. Just inspecting the state delta will do it... In fact, when we have the layering, we can think of the state delta as the result.

So, what if we just didn't have intermediate results for certain simple state updates:

@action(reads=['input_var'], writes=['output_var'])
def simple_action(state: State) -> State:
    output_var = _compute(state['input_var'])
    return state.update(output_var=output_var).append(output_var_list=output_var)

We would determine which we use either based on the annotation or the return type, nd the user would do this knowing that they wouldn't have access to intermediate results in the UI...

Alternatively, we could have them only use the result, and we auto-update the state...

@action(
    reads=['input_var'], 
    writes=[
        update(output_var='output_var'), 
        append(output_var_list='output_var')
    ]
) 
def simple_action(state: State) -> dict:
    return {"output_var" : _compute(state['input_var'])}

Having update as a separate function is just one approach, could have increment and append, or have the default be update

More ideas (in this case I'm adding output_var_list to illustrate append

@action(reads=['input_var'], writes=[update('output_var'), append('output_var_list')])
@action(reads=['input_var'], writes=['output_var', append('output_var_list')]
@action(reads=['input_var'], updates=['output_var'], appends=['output_var_list'])
@action(
    reads=['input_var'], 
    writes=['output_var', 'output_var_list'], 
    update=lambda result: state.update(output_var=result['output_var']).append(output_var_list=result['output_var'])
)

elijahbenizzy avatar Mar 03 '24 18:03 elijahbenizzy

We have decided to do this, just for function-based actions

elijahbenizzy avatar Jun 01 '24 23:06 elijahbenizzy

This is complete

elijahbenizzy avatar Jun 18 '24 23:06 elijahbenizzy