From e401cbbda7e985afdfcf8057bbec5eb33b231b4f Mon Sep 17 00:00:00 2001 From: goutamk09 Date: Tue, 13 Jan 2026 14:03:43 +0530 Subject: [PATCH 1/8] Add override_state_values support to initialize_from --- burr/core/application.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/burr/core/application.py b/burr/core/application.py index 55f98acf..70fa54e4 100644 --- a/burr/core/application.py +++ b/burr/core/application.py @@ -2424,6 +2424,7 @@ def initialize_from( fork_from_app_id: str = None, fork_from_partition_key: str = None, fork_from_sequence_id: int = None, + override_state_values: Optional[dict] = None, ) -> "ApplicationBuilder[StateType]": """Initializes the application we will build from some prior state object. @@ -2460,6 +2461,7 @@ def initialize_from( self.fork_from_app_id = fork_from_app_id self.fork_from_partition_key = fork_from_partition_key self.fork_from_sequence_id = fork_from_sequence_id + self.override_state_values = override_state_values return self def with_state_persister( @@ -2614,6 +2616,9 @@ def _init_state_from_persister( # there was something last_position = load_result["position"] self.state = load_result["state"] + if getattr(self, "override_state_values", None): + self.state = self.state.update(**self.override_state_values) + self.sequence_id = load_result["sequence_id"] status = load_result["status"] if self.resume_at_next_action: From 5c1069382b7056076e232fca6577cdcc5418444e Mon Sep 17 00:00:00 2001 From: goutamk09 Date: Mon, 19 Jan 2026 20:18:53 +0530 Subject: [PATCH 2/8] Add unit test for override_state_values in initialize_from --- tests/core/test_application.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/tests/core/test_application.py b/tests/core/test_application.py index 7e0073dc..be669f67 100644 --- a/tests/core/test_application.py +++ b/tests/core/test_application.py @@ -3725,3 +3725,29 @@ def test_action_2(state: State) -> State: assert sorted(halt_after) == ["test_action", "test_action_2"] assert halt_before == ["test_action"] assert inputs == {} + +def test_initialize_from_applies_override_state_values(): + from burr.core.application import ApplicationBuilder + from burr.core.state import State + from burr.core.persistence import BaseStateLoader + + class FakeStateLoader(BaseStateLoader): + def load(self, partition_key, app_id, sequence_id): + return { + "state": State({"x": 1}), + "position": None, + "sequence_id": 0, + "status": "completed", + } + + builder = ApplicationBuilder().initialize_from( + initializer=FakeStateLoader(), + resume_at_next_action=False, + default_state={}, + default_entrypoint="_start", + override_state_values={"x": 100}, + ) + + app = builder.build() + + assert app.state["x"] == 100 From 1a347ec33acf5217de0202855acbb20161245d07 Mon Sep 17 00:00:00 2001 From: goutamk09 Date: Tue, 20 Jan 2026 19:52:28 +0530 Subject: [PATCH 3/8] Fix test to respect initialize_from entrypoint rules --- tests/core/test_application.py | 36 ++++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/tests/core/test_application.py b/tests/core/test_application.py index be669f67..ab42c77d 100644 --- a/tests/core/test_application.py +++ b/tests/core/test_application.py @@ -23,6 +23,14 @@ import uuid from typing import Any, Awaitable, Callable, Dict, Generator, Literal, Optional, Tuple, Union +from burr.core.application import ApplicationBuilder +from burr.core.state import State +from burr.core.persistence import ( + BaseStatePersister, + BaseStateLoader, + PersistedStateData, +) + import pytest from burr.core import State @@ -3727,10 +3735,6 @@ def test_action_2(state: State) -> State: assert inputs == {} def test_initialize_from_applies_override_state_values(): - from burr.core.application import ApplicationBuilder - from burr.core.state import State - from burr.core.persistence import BaseStateLoader - class FakeStateLoader(BaseStateLoader): def load(self, partition_key, app_id, sequence_id): return { @@ -3740,12 +3744,24 @@ def load(self, partition_key, app_id, sequence_id): "status": "completed", } - builder = ApplicationBuilder().initialize_from( - initializer=FakeStateLoader(), - resume_at_next_action=False, - default_state={}, - default_entrypoint="_start", - override_state_values={"x": 100}, + def list_app_ids(self, partition_key): + return [] + + @action(reads=[], writes=[]) + def noop(state: State) -> State: + return state + + builder = ( + ApplicationBuilder() + .initialize_from( + initializer=FakeStateLoader(), + resume_at_next_action=False, + default_state={}, + default_entrypoint="noop", + override_state_values={"x": 100}, + ) + .with_actions(noop) + .with_transitions() ) app = builder.build() From 0fc27dd3f02ff9b19139598f678662c2d478bef9 Mon Sep 17 00:00:00 2001 From: goutamk09 Date: Tue, 20 Jan 2026 20:25:23 +0530 Subject: [PATCH 4/8] Update application.py --- burr/core/application.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/burr/core/application.py b/burr/core/application.py index 70fa54e4..dc8067c4 100644 --- a/burr/core/application.py +++ b/burr/core/application.py @@ -2616,7 +2616,7 @@ def _init_state_from_persister( # there was something last_position = load_result["position"] self.state = load_result["state"] - if getattr(self, "override_state_values", None): + if self.override_state_values: self.state = self.state.update(**self.override_state_values) self.sequence_id = load_result["sequence_id"] From 661318620e319346131673ede12e69f03ac73dd1 Mon Sep 17 00:00:00 2001 From: Smita Ambiger Date: Tue, 20 Jan 2026 19:52:28 +0530 Subject: [PATCH 5/8] Fix test to respect initialize_from entrypoint rules --- tests/core/test_application.py | 36 ++++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/tests/core/test_application.py b/tests/core/test_application.py index be669f67..ab42c77d 100644 --- a/tests/core/test_application.py +++ b/tests/core/test_application.py @@ -23,6 +23,14 @@ import uuid from typing import Any, Awaitable, Callable, Dict, Generator, Literal, Optional, Tuple, Union +from burr.core.application import ApplicationBuilder +from burr.core.state import State +from burr.core.persistence import ( + BaseStatePersister, + BaseStateLoader, + PersistedStateData, +) + import pytest from burr.core import State @@ -3727,10 +3735,6 @@ def test_action_2(state: State) -> State: assert inputs == {} def test_initialize_from_applies_override_state_values(): - from burr.core.application import ApplicationBuilder - from burr.core.state import State - from burr.core.persistence import BaseStateLoader - class FakeStateLoader(BaseStateLoader): def load(self, partition_key, app_id, sequence_id): return { @@ -3740,12 +3744,24 @@ def load(self, partition_key, app_id, sequence_id): "status": "completed", } - builder = ApplicationBuilder().initialize_from( - initializer=FakeStateLoader(), - resume_at_next_action=False, - default_state={}, - default_entrypoint="_start", - override_state_values={"x": 100}, + def list_app_ids(self, partition_key): + return [] + + @action(reads=[], writes=[]) + def noop(state: State) -> State: + return state + + builder = ( + ApplicationBuilder() + .initialize_from( + initializer=FakeStateLoader(), + resume_at_next_action=False, + default_state={}, + default_entrypoint="noop", + override_state_values={"x": 100}, + ) + .with_actions(noop) + .with_transitions() ) app = builder.build() From 0e58ce49ef4611c361045ff92dcad4c25b571374 Mon Sep 17 00:00:00 2001 From: Smita Ambiger Date: Tue, 20 Jan 2026 20:25:23 +0530 Subject: [PATCH 6/8] Update application.py --- burr/core/application.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/burr/core/application.py b/burr/core/application.py index 70fa54e4..dc8067c4 100644 --- a/burr/core/application.py +++ b/burr/core/application.py @@ -2616,7 +2616,7 @@ def _init_state_from_persister( # there was something last_position = load_result["position"] self.state = load_result["state"] - if getattr(self, "override_state_values", None): + if self.override_state_values: self.state = self.state.update(**self.override_state_values) self.sequence_id = load_result["sequence_id"] From 12773ed5a5ead88ca1332f1f86d0f6f657963654 Mon Sep 17 00:00:00 2001 From: Stefan Krawczyk Date: Sat, 31 Jan 2026 13:02:44 -0800 Subject: [PATCH 7/8] Fixes precommit --- tests/core/test_application.py | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/tests/core/test_application.py b/tests/core/test_application.py index ab42c77d..c90c4067 100644 --- a/tests/core/test_application.py +++ b/tests/core/test_application.py @@ -23,14 +23,6 @@ import uuid from typing import Any, Awaitable, Callable, Dict, Generator, Literal, Optional, Tuple, Union -from burr.core.application import ApplicationBuilder -from burr.core.state import State -from burr.core.persistence import ( - BaseStatePersister, - BaseStateLoader, - PersistedStateData, -) - import pytest from burr.core import State @@ -71,6 +63,7 @@ from burr.core.graph import Graph, GraphBuilder, Transition from burr.core.persistence import ( AsyncDevNullPersister, + BaseStateLoader, BaseStatePersister, DevNullPersister, PersistedStateData, @@ -3734,6 +3727,7 @@ def test_action_2(state: State) -> State: assert halt_before == ["test_action"] assert inputs == {} + def test_initialize_from_applies_override_state_values(): class FakeStateLoader(BaseStateLoader): def load(self, partition_key, app_id, sequence_id): From ebb2e261c3a6aa89f2bce8a12b6bceede185bcfd Mon Sep 17 00:00:00 2001 From: Smita Ambiger Date: Wed, 4 Feb 2026 00:26:10 +0530 Subject: [PATCH 8/8] ui: add toggle to show/hide input nodes in graph view --- .../src/components/routes/app/GraphView.tsx | 47 ++++++++++--------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/telemetry/ui/src/components/routes/app/GraphView.tsx b/telemetry/ui/src/components/routes/app/GraphView.tsx index ce85b823..31a5f37e 100644 --- a/telemetry/ui/src/components/routes/app/GraphView.tsx +++ b/telemetry/ui/src/components/routes/app/GraphView.tsx @@ -20,7 +20,7 @@ import { ActionModel, ApplicationModel, Step } from '../../../api'; import dagre from 'dagre'; -import React, { createContext, useCallback, useLayoutEffect, useRef, useState } from 'react'; +import React, { createContext, useLayoutEffect, useRef, useState } from 'react'; import ReactFlow, { BaseEdge, Controls, @@ -250,7 +250,10 @@ const getLayoutedElements = ( }); }; -const convertApplicationToGraph = (stateMachine: ApplicationModel): [NodeType[], EdgeType[]] => { +const convertApplicationToGraph = ( + stateMachine: ApplicationModel, + showInputs: boolean +): [NodeType[], EdgeType[]] => { const shouldDisplayInput = (input: string) => !input.startsWith('__'); const inputUniqueID = (action: ActionModel, input: string) => `${action.name}:${input}`; // Currently they're distinct by name @@ -285,10 +288,12 @@ const convertApplicationToGraph = (stateMachine: ApplicationModel): [NodeType[], markerEnd: { type: MarkerType.ArrowClosed, width: 20, height: 20 }, data: { from: transition.from_, to: transition.to, condition: transition.condition } })); - return [ - [...allActionNodes, ...allInputNodes], - [...allInputTransitions, ...allTransitionEdges] - ]; + return showInputs + ? [ + [...allActionNodes, ...allInputNodes], + [...allInputTransitions, ...allTransitionEdges] + ] + : [[...allActionNodes], [...allTransitionEdges]]; }; const nodeTypes = { @@ -317,34 +322,25 @@ export const _Graph = (props: { previousActions: Step[] | undefined; hoverAction: Step | undefined; }) => { - const [initialNodes, initialEdges] = React.useMemo(() => { - return convertApplicationToGraph(props.stateMachine); - }, [props.stateMachine]); + const [showInputs, setShowInputs] = useState(true); const [nodes, setNodes] = useState([]); const [edges, setEdges] = useState([]); const { fitView } = useReactFlow(); - const onLayout = useCallback( - ({ direction = 'TB', useInitialNodes = false }): void => { - const opts = { direction }; - const ns = useInitialNodes ? initialNodes : nodes; - const es = useInitialNodes ? initialEdges : edges; + useLayoutEffect(() => { + const [nextNodes, nextEdges] = convertApplicationToGraph(props.stateMachine, showInputs); - getLayoutedElements(ns, es, opts).then(({ nodes: layoutedNodes, edges: layoutedEdges }) => { + getLayoutedElements(nextNodes, nextEdges, { direction: 'TB' }).then( + ({ nodes: layoutedNodes, edges: layoutedEdges }) => { setNodes(layoutedNodes); setEdges(layoutedEdges); window.requestAnimationFrame(() => fitView()); - }); - }, - [nodes, edges] - ); - - useLayoutEffect(() => { - onLayout({ direction: 'TB', useInitialNodes: true }); - }, []); + } + ); + }, [showInputs, props.stateMachine, fitView]); return (
+ +