@@ -122,164 +122,18 @@ When users encounter problems:
122122
123123### 5. Adding Features
124124
125- Common enhancement requests:
125+ See [ api-reference.md ] ( api-reference.md ) for streaming, async, and parallel execution APIs. See [ examples.md ] ( examples.md ) for working code.
126126
127- ** Streaming responses** :
128- ``` python
129- @action (reads = [" input" ], writes = [" output" ])
130- def streaming_action (state : State) -> Generator[State, None , Tuple[dict , State]]:
131- for chunk in stream_data():
132- yield state.update(current_chunk = chunk)
133- result = {" output" : final_result}
134- return result, state.update(** result)
135- ```
136-
137- ** Async actions** :
138- ``` python
139- @action (reads = [" data" ], writes = [" result" ])
140- async def async_action (state : State) -> State:
141- result = await fetch_data()
142- return state.update(result = result)
143- ```
144-
145- ** Parallel execution** :
146- ``` python
147- from burr.core.parallelism import MapStates, RunnableGraph
148-
149- # Apply same action to multiple states
150- class TestMultiplePrompts (MapStates ):
151- def action (self , state : State, inputs : dict ) -> Action | Callable | RunnableGraph:
152- return query_llm.with_name(" query_llm" )
153-
154- def states (self , state : State, context : ApplicationContext, inputs : dict ):
155- for prompt in state[" prompts" ]:
156- yield state.update(prompt = prompt)
157-
158- def reduce (self , state : State, states ):
159- results = [s[" result" ] for s in states]
160- return state.update(all_results = results)
161-
162- @ property
163- def reads (self ) -> list[str ]:
164- return [" prompts" ]
165-
166- @ property
167- def writes (self ) -> list[str ]:
168- return [" all_results" ]
169-
170- app = ApplicationBuilder().with_actions(
171- multi_prompt = TestMultiplePrompts()
172- ).build()
173- ```
174-
175- ## State Management Patterns
176-
177- ### Regular State (Dictionary-Based)
178-
179- ** Reading from state:**
180- ``` python
181- # Use bracket notation to access state values
182- value = state[" key" ]
183- chat_history = state[" chat_history" ]
184- counter = state[" counter" ]
185- ```
186-
187- ** Updating state:**
188- State is immutable. Methods return NEW State objects:
189- ``` python
190- # state.update() - set/update keys, returns new State
191- new_state = state.update(counter = 5 , name = " Alice" )
192-
193- # state.append() - append to lists, returns new State
194- new_state = state.append(chat_history = {" role" : " user" , " content" : " hi" })
195-
196- # state.increment() - increment numbers, returns new State
197- new_state = state.increment(counter = 1 )
198-
199- # Chaining - each method returns a State, enabling fluent patterns
200- new_state = state.update(prompt = prompt).append(chat_history = item)
201- ```
202-
203- ** Action return pattern:**
204- Actions return ` Tuple[dict, State] ` :
205- ``` python
206- from typing import Tuple
207-
208- @action (reads = [" prompt" ], writes = [" response" , " chat_history" ])
209- def ai_respond (state : State) -> Tuple[dict , State]:
210- # 1. Read from state
211- prompt = state[" prompt" ]
212-
213- # 2. Process
214- response = call_llm(prompt)
215-
216- # 3. Return (result_dict, new_state)
217- # result_dict is exposed to callers/tracking
218- # new_state is the updated immutable state
219- return {" response" : response}, state.update(response = response).append(
220- chat_history = {" role" : " assistant" , " content" : response}
221- )
222- ```
223-
224- ** Shorthand (also valid):**
225- ``` python
226- @action (reads = [" counter" ], writes = [" counter" ])
227- def increment (state : State) -> State:
228- result = {" counter" : state[" counter" ] + 1 }
229- # Framework infers result from state updates
230- return state.update(** result)
231- ```
232-
233- ### Pydantic Typed State (Different Pattern)
234-
235- ** Define state model:**
236- ``` python
237- from pydantic import BaseModel, Field
238- from typing import Optional
239-
240- class ApplicationState (BaseModel ):
241- prompt: Optional[str ] = Field(default = None , description = " User prompt" )
242- response: Optional[str ] = Field(default = None , description = " AI response" )
243- chat_history: list[dict ] = Field(default_factory = list )
244- ```
245-
246- ** Configure application:**
247- ``` python
248- from burr.integrations.pydantic import PydanticTypingSystem
249-
250- app = (
251- ApplicationBuilder()
252- .with_typing(PydanticTypingSystem(ApplicationState))
253- .with_state(ApplicationState())
254- .build()
255- )
256- ```
257-
258- ** Access typed state:**
259- ``` python
260- # Use attribute access (not bracket notation)
261- @action.pydantic (reads = [" prompt" ], writes = [" response" ])
262- def ai_respond (state : ApplicationState) -> ApplicationState:
263- # 1. Read using attributes
264- prompt = state.prompt
265-
266- # 2. Process
267- response = call_llm(prompt)
268-
269- # 3. Mutate in-place and return state
270- # (Mutation happens on internal copy)
271- state.response = response
272- return state
273- ```
127+ ## State Management Quick Reference
274128
275- ** Key differences: **
129+ Burr supports two state patterns. See [ patterns.md ] ( patterns.md ) for full details and examples.
276130
277131| Aspect | Regular State | Pydantic Typed State |
278132| --------| ---------------| ---------------------|
279133| ** Access** | ` state["key"] ` | ` state.key ` |
280134| ** Return** | ` Tuple[dict, State] ` | ` ApplicationState ` |
281135| ** Decorator** | ` @action(reads=[], writes=[]) ` | ` @action.pydantic(reads=[], writes=[]) ` |
282- | ** Updates** | Must use ` .update() ` , ` .append() ` | In-place mutation |
136+ | ** Updates** | ` .update() ` , ` .append() ` , ` .increment ()` | In-place mutation |
283137| ** Type Safety** | Runtime only | IDE support + validation |
284138
285139## Code Quality Standards
@@ -298,7 +152,7 @@ When writing or reviewing Apache Burr code:
298152- ** Loops** : Use recursive transitions with conditions
299153- ** Error handling** : Create error actions and transition to them on failure
300154- ** Multi-step workflows** : Chain actions with clear single responsibilities
301- - ** State persistence** : Use ` SQLLitePersister ` or ` initialize_from ` for resumability
155+ - ** State persistence** : Use ` SQLitePersister ` or ` initialize_from ` for resumability
302156- ** Observability** : Always include ` .with_tracker() ` for the Burr UI
303157
304158## Integration Scenarios
0 commit comments