Skip to content

Commit

Permalink
Fixes up state typing docs
Browse files Browse the repository at this point in the history
Adds in some that were left out + rounds out the docs
  • Loading branch information
elijahbenizzy committed Sep 18, 2024
1 parent cc3b323 commit 9587699
Show file tree
Hide file tree
Showing 5 changed files with 147 additions and 7 deletions.
120 changes: 120 additions & 0 deletions docs/concepts/state-typing.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
.. _statetyping:

============
Typing State
============

.. note::

Burr allows you to specify types for your state. This enables more self-documenting, easy-to-write actions,
allows you to type your entire application object for downstream consumption, and provides a way to inspect
the state of your application prior to execution (for use by a web-server/other typing system). This is done
through the use of pydantic schemas.

For a quick-start guide, see the `example <https://github.com/DAGWorks-Inc/burr/tree/main/examples/typed-state>`_


Burr has two approaches to specifying a schema for a state. These can work together as long as they specify clashing state:

1. Application-level typing
2. Action-level typing

These enable a host of other extensions/capabilities.

While these are built for pydantic, the typing system is intended to be pluggable, and we plan to add further integrations
(dataclasses, typed dicts, etc...).


Application-level Typing
------------------------

To type at the application level, you can use the :py:meth:`ApplicationBuilder.with_typing burr.core.application.ApplicationBuilder.with_typing` method.
This takes in a :py:class:`TypingSystem burr.core.typing.TypingSystem` object, which specifies how to gather types from/assign types to the state.

This looks as follows:

First, define a pydantic model for your application:

.. code-block:: python
from pydantic import BaseModel
class ApplicationState(pydantic.BaseModel):
chat_history: List[dict[str, str]] = pydantic.Field(default_factory=list)
prompt: Optional[str] = None
mode: Optional[Literal["text", "image"]] = None
response: Optional[dict[str, str]] = None
Then, we can use this model to type our application:

.. code-block:: python
from burr import ApplicationBuilder
from burr.core.typing import PydanticTypingSystem
app = (
ApplicationBuilder()
.with_actions(...)
.with_entrypoint(...)
.with_transitions(...)
.with_typing(PydanticTypingSystem(ApplicationState))
.with_state(ApplicationState())
.build()
)
Your application is now typed with that pydantic model. If you're using an appropriate typing
integration in your IDE (E.G. pylance), it will know that the state of your application is of type
``MyApplicationState``.

When you have this you'll be able to run:

.. code-block:: python
action_ran, result, state = app.run(inputs=...)
state.data # of type ApplicationState -- do what you want with this!
Action-level typing
-------------------

You can also define type computations on on the action-level:

.. code-block:: python
@pydantic_action(reads=["prompt", "chat_history"], writes=["response"])
def image_response(state: ApplicationState, model: str = "dall-e-2") -> ApplicationState:
client = _get_openai_client()
result = client.images.generate(
model=model, prompt=state.prompt, size="1024x1024", quality="standard", n=1
)
response = result.data[0].url
state.response = {"content": response, "type": MODES[state.mode], "role": "assistant"}
return state
Note three interesting choices here:

1. The state is typed as a pydantic model
2. The return type is the same pydantic model
3. We mutate the state in place, rather than returning a new state

This is a different action API -- it effectively subsets the state on input,
gives you that object, then subsets the state on output, and merges it back.

Thus if you try to refer to a state variable that you didn't specify in the reads/writes,
it will give an error.

Mutating in place is OK as this produces a new object for each execution run. For now, you will
want to be careful about lists/list pointers -- we are working on that.


Application + Action-level typing
---------------------------------

Application-level typing has the benefit of giving you application-level IDE autocompletion and allowing you to specify
the schema. Action level typing makes it easier to write actions, and allows for more flexible/modular actions without specifying
the whole state in advance.

You can use them both as long as the types match up. If not, this will error out.

.. note::

We have not yet implemented validation on more than just the action level -- this is coming soon!
5 changes: 3 additions & 2 deletions docs/reference/integrations/index.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
================
============
Integrations
================
============

Integrations -- we will be adding more

Expand All @@ -12,3 +12,4 @@ Integrations -- we will be adding more
opentelemetry
traceloop
langchain
pydantic
6 changes: 3 additions & 3 deletions docs/reference/integrations/langchain.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
----------------
Burr + Langchain
----------------
---------
Langchain
---------

Burr works out of the box with langchain, as Burr delegates to any python code.

Expand Down
4 changes: 2 additions & 2 deletions docs/reference/serde.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
.. _serderef:

==================================
Serialization & Deserialization
==================================
Expand All @@ -21,8 +23,6 @@ This is used to identify the deserialization function to use.
Out of the box Implementations
==============================

.. _serderef:

The following implementations are available assuming you have the right dependencies in your environment:

LangChain Objects
Expand Down
19 changes: 19 additions & 0 deletions docs/reference/typing.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
.. _statetypingref:

======
Typing
======

Reference on the State typing API. Note that docs here are for both core burr and the pydantic plugin
(which does the interesting typing). For an overview, read :ref:`statetyping`.


.. autoclass:: burr.core.typing.TypingSystem
:members:

.. automethod:: __init__

.. autoclass:: burr.integrations.pydantic.PydanticTypingSystem
:members:

.. automethod:: __init__

0 comments on commit 9587699

Please sign in to comment.