Skip to content

Commit 5e0dd10

Browse files
authored
Merge pull request #46 from aurelio-labs/james/starlette-compat
feat: add direct starlette support for GraphEvent
2 parents 56165a9 + 168d1bc commit 5e0dd10

4 files changed

Lines changed: 52 additions & 2 deletions

File tree

docs/user-guide/faqs.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
2+
## TypeError: object dict can't be used in 'await' expression
3+
4+
This is a common mistake when defining the graph. The internals of `graphai` expect _all_ nodes to be defined with `async def`. When defining a node with `def` we will see this error:
5+
6+
```
7+
Traceback (most recent call last):
8+
File "/app/.venv/lib/python3.13/site-packages/graphai/graph.py", line 351, in execute
9+
output = await current_node.invoke(input=state, state=self.state)
10+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
11+
File "/app/.venv/lib/python3.13/site-packages/graphai/nodes/base.py", line 152, in invoke
12+
out = await instance.execute(**input)
13+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
14+
File "/app/.venv/lib/python3.13/site-packages/graphai/nodes/base.py", line 74, in execute
15+
return await func(**params_dict) # Pass only the necessary arguments
16+
^^^^^^^^^^^^^^^^^^^^^^^^^
17+
TypeError: object dict can't be used in 'await' expression
18+
```
19+
20+
The solution is to always define nodes using `async def`. For example:
21+
22+
```python
23+
24+
# WRONG:
25+
@node
26+
def my_node(input: dict) -> dict:
27+
return {"output": "Hello, world!"}
28+
29+
# DO THIS INSTEAD:
30+
@node
31+
async def my_node(input: dict) -> dict:
32+
return {"output": "Hello, world!"}
33+
```

graphai/callback.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import asyncio
22
from dataclasses import dataclass
33
from enum import Enum
4+
import json
45
from pydantic import Field
56
from typing import Any
67
from collections.abc import AsyncIterator
@@ -43,6 +44,22 @@ class GraphEvent:
4344
token: str | None = None
4445
params: dict[str, Any] | None = None
4546

47+
def encode(self, charset: str = "utf-8") -> bytes:
48+
"""Encodes the event as a JSON string, important for compatability with FastAPI
49+
and starlette.
50+
51+
:param charset: The character set to use for encoding the event.
52+
:type charset: str
53+
"""
54+
event_dict = {
55+
"type": self.type.value if hasattr(self.type, "value") else str(self.type),
56+
"identifier": self.identifier,
57+
"token": self.token,
58+
"params": self.params,
59+
}
60+
data = f"data: {json.dumps(event_dict, ensure_ascii=False, separators=(',', ':'))}\n\n"
61+
return data.encode(charset)
62+
4663

4764
class Callback:
4865
"""The original callback handler class. Outputs a stream of structured text

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "graphai-lib"
3-
version = "0.0.9"
3+
version = "0.0.10rc1"
44
description = "Not an AI framework"
55
readme = "README.md"
66
requires-python = ">=3.10,<3.14"

uv.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)