langgraph-stream-parser 0.1.7__tar.gz → 0.2.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- langgraph_stream_parser-0.2.1/.github/workflows/ci.yml +37 -0
- langgraph_stream_parser-0.2.1/.github/workflows/release.yml +32 -0
- {langgraph_stream_parser-0.1.7 → langgraph_stream_parser-0.2.1}/CHANGELOG.md +37 -0
- {langgraph_stream_parser-0.1.7 → langgraph_stream_parser-0.2.1}/PKG-INFO +96 -10
- {langgraph_stream_parser-0.1.7 → langgraph_stream_parser-0.2.1}/README.md +88 -7
- langgraph_stream_parser-0.2.1/assets/header.svg +87 -0
- {langgraph_stream_parser-0.1.7 → langgraph_stream_parser-0.2.1}/pyproject.toml +13 -3
- {langgraph_stream_parser-0.1.7 → langgraph_stream_parser-0.2.1}/src/langgraph_stream_parser/__init__.py +17 -2
- {langgraph_stream_parser-0.1.7 → langgraph_stream_parser-0.2.1}/src/langgraph_stream_parser/adapters/__init__.py +3 -0
- {langgraph_stream_parser-0.1.7 → langgraph_stream_parser-0.2.1}/src/langgraph_stream_parser/adapters/base.py +10 -0
- langgraph_stream_parser-0.2.1/src/langgraph_stream_parser/adapters/session.py +256 -0
- {langgraph_stream_parser-0.1.7 → langgraph_stream_parser-0.2.1}/src/langgraph_stream_parser/compat.py +32 -0
- langgraph_stream_parser-0.2.1/src/langgraph_stream_parser/demo/__init__.py +15 -0
- langgraph_stream_parser-0.2.1/src/langgraph_stream_parser/demo/agent.py +102 -0
- {langgraph_stream_parser-0.1.7 → langgraph_stream_parser-0.2.1}/src/langgraph_stream_parser/events.py +201 -26
- langgraph_stream_parser-0.2.1/src/langgraph_stream_parser/extractors/__init__.py +29 -0
- langgraph_stream_parser-0.2.1/src/langgraph_stream_parser/extractors/builtins.py +384 -0
- {langgraph_stream_parser-0.1.7 → langgraph_stream_parser-0.2.1}/src/langgraph_stream_parser/extractors/messages.py +72 -5
- {langgraph_stream_parser-0.1.7 → langgraph_stream_parser-0.2.1}/src/langgraph_stream_parser/handlers/messages.py +29 -13
- {langgraph_stream_parser-0.1.7 → langgraph_stream_parser-0.2.1}/src/langgraph_stream_parser/handlers/updates.py +81 -6
- langgraph_stream_parser-0.2.1/src/langgraph_stream_parser/host/__init__.py +16 -0
- langgraph_stream_parser-0.2.1/src/langgraph_stream_parser/host/__main__.py +17 -0
- langgraph_stream_parser-0.2.1/src/langgraph_stream_parser/host/config.py +291 -0
- langgraph_stream_parser-0.2.1/src/langgraph_stream_parser/host/loader.py +83 -0
- langgraph_stream_parser-0.2.1/src/langgraph_stream_parser/host/workspace.py +42 -0
- {langgraph_stream_parser-0.1.7 → langgraph_stream_parser-0.2.1}/src/langgraph_stream_parser/parser.py +14 -7
- {langgraph_stream_parser-0.1.7 → langgraph_stream_parser-0.2.1}/tests/fixtures/mocks.py +102 -0
- {langgraph_stream_parser-0.1.7 → langgraph_stream_parser-0.2.1}/tests/test_compat.py +26 -0
- langgraph_stream_parser-0.2.1/tests/test_demo.py +36 -0
- {langgraph_stream_parser-0.1.7 → langgraph_stream_parser-0.2.1}/tests/test_events.py +63 -2
- {langgraph_stream_parser-0.1.7 → langgraph_stream_parser-0.2.1}/tests/test_extractors.py +166 -1
- langgraph_stream_parser-0.2.1/tests/test_generic_extractor.py +195 -0
- langgraph_stream_parser-0.2.1/tests/test_host.py +149 -0
- langgraph_stream_parser-0.2.1/tests/test_host_config.py +120 -0
- langgraph_stream_parser-0.2.1/tests/test_lc14_compat.py +99 -0
- {langgraph_stream_parser-0.1.7 → langgraph_stream_parser-0.2.1}/tests/test_parser.py +19 -18
- langgraph_stream_parser-0.2.1/tests/test_real_model.py +81 -0
- langgraph_stream_parser-0.2.1/tests/test_reasoning_display.py +205 -0
- langgraph_stream_parser-0.2.1/tests/test_session_adapter.py +287 -0
- langgraph_stream_parser-0.2.1/tests/test_wire_contract.py +140 -0
- {langgraph_stream_parser-0.1.7 → langgraph_stream_parser-0.2.1}/uv.lock +77 -18
- langgraph_stream_parser-0.1.7/.claude/settings.local.json +0 -20
- langgraph_stream_parser-0.1.7/src/langgraph_stream_parser/extractors/__init__.py +0 -15
- langgraph_stream_parser-0.1.7/src/langgraph_stream_parser/extractors/builtins.py +0 -166
- {langgraph_stream_parser-0.1.7 → langgraph_stream_parser-0.2.1}/.gitignore +0 -0
- {langgraph_stream_parser-0.1.7 → langgraph_stream_parser-0.2.1}/LICENSE +0 -0
- {langgraph_stream_parser-0.1.7 → langgraph_stream_parser-0.2.1}/examples/agent.py +0 -0
- {langgraph_stream_parser-0.1.7 → langgraph_stream_parser-0.2.1}/examples/fastapi_websocket.py +0 -0
- {langgraph_stream_parser-0.1.7 → langgraph_stream_parser-0.2.1}/examples/jupyter_example.ipynb +0 -0
- {langgraph_stream_parser-0.1.7 → langgraph_stream_parser-0.2.1}/spec.md +0 -0
- {langgraph_stream_parser-0.1.7 → langgraph_stream_parser-0.2.1}/src/langgraph_stream_parser/adapters/cli.py +0 -0
- {langgraph_stream_parser-0.1.7 → langgraph_stream_parser-0.2.1}/src/langgraph_stream_parser/adapters/fastapi.py +0 -0
- {langgraph_stream_parser-0.1.7 → langgraph_stream_parser-0.2.1}/src/langgraph_stream_parser/adapters/jupyter.py +0 -0
- {langgraph_stream_parser-0.1.7 → langgraph_stream_parser-0.2.1}/src/langgraph_stream_parser/adapters/print.py +0 -0
- {langgraph_stream_parser-0.1.7 → langgraph_stream_parser-0.2.1}/src/langgraph_stream_parser/extractors/base.py +0 -0
- {langgraph_stream_parser-0.1.7 → langgraph_stream_parser-0.2.1}/src/langgraph_stream_parser/extractors/interrupts.py +0 -0
- {langgraph_stream_parser-0.1.7 → langgraph_stream_parser-0.2.1}/src/langgraph_stream_parser/handlers/__init__.py +0 -0
- {langgraph_stream_parser-0.1.7 → langgraph_stream_parser-0.2.1}/src/langgraph_stream_parser/resume.py +0 -0
- {langgraph_stream_parser-0.1.7 → langgraph_stream_parser-0.2.1}/tests/__init__.py +0 -0
- {langgraph_stream_parser-0.1.7 → langgraph_stream_parser-0.2.1}/tests/fixtures/__init__.py +0 -0
- {langgraph_stream_parser-0.1.7 → langgraph_stream_parser-0.2.1}/tests/test_cli_adapter.py +0 -0
- {langgraph_stream_parser-0.1.7 → langgraph_stream_parser-0.2.1}/tests/test_dual_mode.py +0 -0
- {langgraph_stream_parser-0.1.7 → langgraph_stream_parser-0.2.1}/tests/test_fastapi_adapter.py +0 -0
- {langgraph_stream_parser-0.1.7 → langgraph_stream_parser-0.2.1}/tests/test_jupyter.py +0 -0
- {langgraph_stream_parser-0.1.7 → langgraph_stream_parser-0.2.1}/tests/test_print_adapter.py +0 -0
- {langgraph_stream_parser-0.1.7 → langgraph_stream_parser-0.2.1}/tests/test_resume.py +0 -0
- {langgraph_stream_parser-0.1.7 → langgraph_stream_parser-0.2.1}/tests/test_subagent.py +0 -0
- {langgraph_stream_parser-0.1.7 → langgraph_stream_parser-0.2.1}/tests/test_v2_stream.py +0 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
test:
|
|
11
|
+
runs-on: ${{ matrix.os }}
|
|
12
|
+
strategy:
|
|
13
|
+
fail-fast: false
|
|
14
|
+
matrix:
|
|
15
|
+
os: [ubuntu-latest]
|
|
16
|
+
python-version: ["3.10", "3.11", "3.12", "3.13"]
|
|
17
|
+
include:
|
|
18
|
+
# One Windows job for cross-platform coverage (primary dev env).
|
|
19
|
+
- os: windows-latest
|
|
20
|
+
python-version: "3.12"
|
|
21
|
+
|
|
22
|
+
steps:
|
|
23
|
+
- uses: actions/checkout@v4
|
|
24
|
+
|
|
25
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
26
|
+
uses: actions/setup-python@v5
|
|
27
|
+
with:
|
|
28
|
+
python-version: ${{ matrix.python-version }}
|
|
29
|
+
|
|
30
|
+
- name: Install uv
|
|
31
|
+
uses: astral-sh/setup-uv@v3
|
|
32
|
+
|
|
33
|
+
- name: Install
|
|
34
|
+
run: uv pip install --system -e ".[dev]"
|
|
35
|
+
|
|
36
|
+
- name: Test
|
|
37
|
+
run: pytest -ra --cov=langgraph_stream_parser --cov-report=term-missing
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
# Mirrors the deepagent-hermes release.yml: tag-driven publish to PyPI.
|
|
4
|
+
# Tag any commit with `v*` (e.g. `v0.2.1`) and this builds + uploads.
|
|
5
|
+
|
|
6
|
+
on:
|
|
7
|
+
push:
|
|
8
|
+
tags:
|
|
9
|
+
- "v*"
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
publish:
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
steps:
|
|
15
|
+
- uses: actions/checkout@v4
|
|
16
|
+
- uses: actions/setup-python@v5
|
|
17
|
+
with:
|
|
18
|
+
python-version: "3.13"
|
|
19
|
+
- name: Install build
|
|
20
|
+
run: pip install build
|
|
21
|
+
- name: Build wheel + sdist
|
|
22
|
+
# `python -m build` (no flag) runs sdist → wheel-from-sdist,
|
|
23
|
+
# matching the publish path local pre-flight checks should
|
|
24
|
+
# exercise. See deepagent-hermes v0.1.2 incident for why this
|
|
25
|
+
# matters: a wheel built directly with --wheel can ship fine
|
|
26
|
+
# while the wheel-from-sdist drops every Python file because
|
|
27
|
+
# of a restrictive [tool.hatch.build.targets.sdist] include.
|
|
28
|
+
run: python -m build
|
|
29
|
+
- name: Publish to PyPI
|
|
30
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
31
|
+
with:
|
|
32
|
+
password: ${{ secrets.PYPI_API_TOKEN }}
|
|
@@ -1,5 +1,42 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.1.9] - 2026-05-19
|
|
4
|
+
|
|
5
|
+
Compatibility refresh for **langgraph 1.2**, **langchain-core 1.4**, and **deepagents 0.6**.
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
- `UsageEvent.cache_read_tokens` and `UsageEvent.cache_creation_tokens` — populated from `usage_metadata.input_token_details` (`cache_read`, `cache_creation`). Default 0; omitted from `to_dict()` when zero.
|
|
9
|
+
- `ContentEvent.is_subagent` and `ReasoningEvent.is_subagent` — set to `True` when stream metadata carries `ls_agent_type == "subagent"` (deepagents >= 0.6). Lets consumers distinguish subagent output even when `lc_agent_name` is absent.
|
|
10
|
+
- `"respond"` decision support in `InterruptEvent.build_decisions()` / `create_resume()`: pass `response="..."` to send a text reply in place of the tool call. Matches the deepagents 0.6 decision verb set.
|
|
11
|
+
- `InterruptEvent.build_decisions(..., use_edited_action=False)` escape hatch for runtimes that still expect the legacy `{"type": "edit", "args": ...}` resume shape.
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
- `extract_message_content()` now skips the full set of non-text content blocks defined by langchain-core 1.4 standard content blocks: `tool_call`, `tool_use`, `tool_call_chunk`, `server_tool_call`, `server_tool_call_chunk`, `server_tool_result`, `invalid_tool_call`, `image`, `audio`, `video`, `file` (plus the existing `reasoning` / `thinking`). Previously these could leak as stringified dicts into `ContentEvent.content`. Tool lifecycle and reasoning events are unchanged.
|
|
15
|
+
- `InterruptEvent.build_decisions("edit", ...)` now emits the modern `{"type": "edit", "edited_action": {"name", "args"}}` shape by default, matching LangGraph 1.1+ / deepagents 0.5+. Set `use_edited_action=False` for the legacy shape.
|
|
16
|
+
- `InterruptEvent.allowed_decisions` defaults to `{"approve", "reject", "edit", "respond"}` when no review configs are present (was `{"approve", "reject"}`).
|
|
17
|
+
- Dev dependency bumped: `langgraph>=1.1.0`, `langchain-core>=1.4.0`.
|
|
18
|
+
|
|
19
|
+
### Notes
|
|
20
|
+
- **No breaking change for default tool extractors**: deepagents 0.6 ships new built-in tools (`glob_search`, `grep_search`, `execute`, `start_async_task` / `check_async_task` / `update_async_task` / `cancel_async_task` / `list_async_tasks`, plus QuickJS `CodeInterpreterMiddleware`). These flow through the regular `ToolCallStartEvent` / `ToolCallEndEvent` lifecycle — no parser change required.
|
|
21
|
+
- **v3 `stream_events` typed projections** (LangGraph 1.2 beta) are not yet supported. v2 `StreamPart` parsing remains the recommended path for `stream()` / `astream()`.
|
|
22
|
+
|
|
23
|
+
## [0.1.8] - 2026-04-18
|
|
24
|
+
|
|
25
|
+
### Added
|
|
26
|
+
- `ReasoningEvent` dataclass for reasoning / thinking content; emitted from langchain-core `reasoning` and `thinking` content blocks, and from `think_tool` reflections. Carries a `source` field (`"content_block"` or `"think_tool"`) so UIs can distinguish provenance.
|
|
27
|
+
- `DisplayEvent` dataclass for rich inline content (dataframes, images, plotly, html, json) from `display_inline`-style tools. Carries `display_type`, `data`, `title`, `status`, `error`, `tool_name`, `tool_call_id`, `node`, `namespace`.
|
|
28
|
+
- `extract_reasoning_content()` helper in `extractors.messages` for parsing reasoning blocks from `AIMessageChunk.content`.
|
|
29
|
+
- `UpdatesHandler._event_from_extraction()` routes extractor output to typed events; unknown `extracted_type` values still flow through `ToolExtractedEvent` for custom extractors.
|
|
30
|
+
- README sections: "Reasoning & Thinking" and "Rich Inline Display" with typed matching examples.
|
|
31
|
+
|
|
32
|
+
### Changed
|
|
33
|
+
- `think_tool` output is now a `ReasoningEvent(source="think_tool")` instead of `ToolExtractedEvent(extracted_type="reflection")`. Legacy dict API (`stream_graph_updates`) still produces `{"chunk": text}` for backward compatibility.
|
|
34
|
+
- `display_inline` tool output is now a `DisplayEvent` instead of `ToolExtractedEvent(extracted_type="display_inline")`.
|
|
35
|
+
- `extract_message_content()` now skips reasoning blocks so they can be surfaced as `ReasoningEvent` separately.
|
|
36
|
+
|
|
37
|
+
### Fixed
|
|
38
|
+
- Removed dead `has_messages` variable in `_parse_v2`.
|
|
39
|
+
|
|
3
40
|
## [0.1.7] - 2026-04-18
|
|
4
41
|
|
|
5
42
|
### Added
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: langgraph-stream-parser
|
|
3
|
-
Version: 0.1
|
|
3
|
+
Version: 0.2.1
|
|
4
4
|
Summary: Universal parser for LangGraph streaming outputs
|
|
5
5
|
Project-URL: Homepage, https://github.com/dkedar7/langgraph-stream-parser
|
|
6
6
|
Project-URL: Documentation, https://github.com/dkedar7/langgraph-stream-parser#readme
|
|
@@ -20,11 +20,13 @@ Classifier: Programming Language :: Python :: 3.12
|
|
|
20
20
|
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
21
21
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
22
22
|
Requires-Python: >=3.10
|
|
23
|
+
Provides-Extra: demo
|
|
24
|
+
Requires-Dist: deepagents>=0.3; extra == 'demo'
|
|
23
25
|
Provides-Extra: dev
|
|
24
26
|
Requires-Dist: fastapi>=0.100; extra == 'dev'
|
|
25
27
|
Requires-Dist: httpx>=0.25; extra == 'dev'
|
|
26
|
-
Requires-Dist: langchain-core>=
|
|
27
|
-
Requires-Dist: langgraph>=
|
|
28
|
+
Requires-Dist: langchain-core>=1.4.0; extra == 'dev'
|
|
29
|
+
Requires-Dist: langgraph>=1.1.0; extra == 'dev'
|
|
28
30
|
Requires-Dist: pytest-asyncio>=0.21; extra == 'dev'
|
|
29
31
|
Requires-Dist: pytest-cov>=4.0; extra == 'dev'
|
|
30
32
|
Requires-Dist: pytest>=7.0; extra == 'dev'
|
|
@@ -34,8 +36,15 @@ Requires-Dist: fastapi>=0.100; extra == 'fastapi'
|
|
|
34
36
|
Provides-Extra: jupyter
|
|
35
37
|
Requires-Dist: ipython>=8.0; extra == 'jupyter'
|
|
36
38
|
Requires-Dist: rich>=13.0; extra == 'jupyter'
|
|
39
|
+
Provides-Extra: real
|
|
40
|
+
Requires-Dist: langchain-openai>=0.2; extra == 'real'
|
|
41
|
+
Requires-Dist: langgraph>=1.1.0; extra == 'real'
|
|
37
42
|
Description-Content-Type: text/markdown
|
|
38
43
|
|
|
44
|
+
<p align="center">
|
|
45
|
+
<img src="assets/header.svg" alt="langgraph-stream-parser" width="100%">
|
|
46
|
+
</p>
|
|
47
|
+
|
|
39
48
|
# langgraph-stream-parser
|
|
40
49
|
|
|
41
50
|
Universal parser for LangGraph streaming outputs. Normalizes complex, variable output shapes from `graph.stream()` and `graph.astream()` into consistent, typed event objects.
|
|
@@ -81,13 +90,17 @@ for event in parser.parse(graph.stream(input_data, stream_mode="updates")):
|
|
|
81
90
|
| Event | Description |
|
|
82
91
|
|-------|-------------|
|
|
83
92
|
| `ContentEvent` | Text content from AI messages. Includes `agent_name` when from a deep agent subagent. |
|
|
93
|
+
| `ReasoningEvent` | Reasoning / thinking text — from langchain-core `reasoning` content blocks or `think_tool` reflections |
|
|
84
94
|
| `ToolCallStartEvent` | Tool call initiated by AI |
|
|
85
95
|
| `ToolCallEndEvent` | Tool call completed with result |
|
|
86
|
-
| `ToolExtractedEvent` | Special content extracted from tool (e.g.,
|
|
96
|
+
| `ToolExtractedEvent` | Special content extracted from tool (e.g., todos, custom extractors) |
|
|
97
|
+
| `DisplayEvent` | Rich inline content (dataframe, image, plotly, html, json) from `display_inline`-style tools |
|
|
87
98
|
| `InterruptEvent` | Human-in-the-loop interrupt requiring decision |
|
|
88
99
|
| `StateUpdateEvent` | Non-message state updates (opt-in) |
|
|
89
|
-
| `UsageEvent` | Token usage metadata (input/output/total tokens) |
|
|
100
|
+
| `UsageEvent` | Token usage metadata (input/output/total/cache_read/cache_creation tokens) |
|
|
90
101
|
| `CustomEvent` | Custom data emitted via `get_stream_writer()` |
|
|
102
|
+
| `ValuesEvent` | Full state snapshot from `stream_mode="values"` (v2) |
|
|
103
|
+
| `DebugEvent` | Debug, checkpoint, or task trace from v2 streaming |
|
|
91
104
|
| `CompleteEvent` | Stream finished successfully |
|
|
92
105
|
| `ErrorEvent` | Error during streaming |
|
|
93
106
|
|
|
@@ -169,6 +182,22 @@ for event in parser.parse(graph.stream(input_data, config=config)):
|
|
|
169
182
|
break
|
|
170
183
|
```
|
|
171
184
|
|
|
185
|
+
Supported decision types (deepagents 0.6+ / LangGraph 1.1+): `"approve"`, `"reject"`, `"edit"`, `"respond"`.
|
|
186
|
+
|
|
187
|
+
```python
|
|
188
|
+
# Edit args before approval — emits the modern ``edited_action`` shape
|
|
189
|
+
resume = event.create_resume(
|
|
190
|
+
"edit",
|
|
191
|
+
args_modifier=lambda args: {**args, "safe": True},
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
# Reply with text in place of running the tool
|
|
195
|
+
resume = event.create_resume("respond", response="Please rephrase that.")
|
|
196
|
+
|
|
197
|
+
# For older LangGraph runtimes that expect ``{"type": "edit", "args": ...}``:
|
|
198
|
+
resume = event.create_resume("edit", args_modifier=fn, use_edited_action=False)
|
|
199
|
+
```
|
|
200
|
+
|
|
172
201
|
### Custom Tool Extractors
|
|
173
202
|
|
|
174
203
|
```python
|
|
@@ -251,12 +280,14 @@ for event in parser.parse(stream):
|
|
|
251
280
|
print(event.content, end="")
|
|
252
281
|
```
|
|
253
282
|
|
|
254
|
-
For [LangChain deep agents](https://docs.langchain.com/oss/python/deepagents/subagents), `ContentEvent.agent_name` is extracted from `lc_agent_name` metadata:
|
|
283
|
+
For [LangChain deep agents](https://docs.langchain.com/oss/python/deepagents/subagents), `ContentEvent.agent_name` is extracted from `lc_agent_name` metadata, and `ContentEvent.is_subagent` is set to `True` when deepagents (>= 0.6) tags the run with `ls_agent_type="subagent"`. Match on either signal:
|
|
255
284
|
|
|
256
285
|
```python
|
|
257
|
-
case ContentEvent(content=text, agent_name=name):
|
|
258
|
-
label = f"[{name}] "
|
|
286
|
+
case ContentEvent(content=text, agent_name=name, is_subagent=True):
|
|
287
|
+
label = f"[{name or 'subagent'}] "
|
|
259
288
|
print(f"{label}{text}", end="")
|
|
289
|
+
case ContentEvent(content=text):
|
|
290
|
+
print(text, end="")
|
|
260
291
|
```
|
|
261
292
|
|
|
262
293
|
### Custom Stream Mode
|
|
@@ -272,6 +303,60 @@ for event in parser.parse(stream):
|
|
|
272
303
|
print(f"Progress: {data}")
|
|
273
304
|
```
|
|
274
305
|
|
|
306
|
+
### Reasoning & Thinking
|
|
307
|
+
|
|
308
|
+
Reasoning content arrives as a distinct `ReasoningEvent` so UIs can render it differently from the final answer (greyed out, collapsed, etc.). Two sources, same event type:
|
|
309
|
+
|
|
310
|
+
```python
|
|
311
|
+
for event in parser.parse(stream):
|
|
312
|
+
match event:
|
|
313
|
+
case ReasoningEvent(content=text, source="content_block"):
|
|
314
|
+
# From langchain-core reasoning blocks (Anthropic thinking,
|
|
315
|
+
# OpenAI reasoning summaries). Streamed token-by-token.
|
|
316
|
+
print(f"\033[90m{text}\033[0m", end="") # grey
|
|
317
|
+
case ReasoningEvent(content=text, source="think_tool"):
|
|
318
|
+
# From the built-in think_tool ThinkToolExtractor.
|
|
319
|
+
print(f"💭 {text}")
|
|
320
|
+
case ContentEvent(content=text):
|
|
321
|
+
print(text, end="")
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
### Rich Inline Display
|
|
325
|
+
|
|
326
|
+
For agents that need to show DataFrames, charts, images, or HTML in the transcript, use a `display_inline`-style tool. The parser recognizes the convention and emits a typed `DisplayEvent` — no stringified dict hacks.
|
|
327
|
+
|
|
328
|
+
**Tool side** — return a JSON string with `display_type`, `data`, `title`, `status`:
|
|
329
|
+
|
|
330
|
+
```python
|
|
331
|
+
def show_dataframe(df_name: str) -> str:
|
|
332
|
+
import json
|
|
333
|
+
df = load(df_name)
|
|
334
|
+
return json.dumps({
|
|
335
|
+
"type": "display_inline",
|
|
336
|
+
"display_type": "dataframe",
|
|
337
|
+
"title": df_name,
|
|
338
|
+
"data": df.to_html(), # or fig.to_json() for plotly,
|
|
339
|
+
"status": "success", # base64 PNG for matplotlib, etc.
|
|
340
|
+
})
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
Configure your LangGraph tool registration with `name="display_inline"` (or register a custom `DisplayInlineExtractor` for a different name).
|
|
344
|
+
|
|
345
|
+
**Consumer side** — match on `DisplayEvent`:
|
|
346
|
+
|
|
347
|
+
```python
|
|
348
|
+
for event in parser.parse(stream):
|
|
349
|
+
match event:
|
|
350
|
+
case DisplayEvent(display_type="dataframe", data=html, title=title):
|
|
351
|
+
ui.show_html(f"<h3>{title}</h3>{html}")
|
|
352
|
+
case DisplayEvent(display_type="plotly", data=plotly_json):
|
|
353
|
+
ui.show_plotly(json.loads(plotly_json))
|
|
354
|
+
case DisplayEvent(display_type=kind, data=data):
|
|
355
|
+
ui.show_generic(kind, data)
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
The `display_type` field is consumer-defined — any string the tool and UI agree on. Common values: `"dataframe"`, `"image"`, `"plotly"`, `"html"`, `"json"`.
|
|
359
|
+
|
|
275
360
|
### Configuration Options
|
|
276
361
|
|
|
277
362
|
```python
|
|
@@ -453,16 +538,17 @@ The package includes extractors for common LangGraph tools:
|
|
|
453
538
|
|
|
454
539
|
- **ThinkToolExtractor**: Extracts reflections from `think_tool`
|
|
455
540
|
- **TodoExtractor**: Extracts todo lists from `write_todos`
|
|
541
|
+
- **DisplayInlineExtractor**: Extracts inline display artifacts from `display_inline`
|
|
456
542
|
|
|
457
543
|
## Examples
|
|
458
544
|
|
|
459
545
|
### FastAPI WebSocket Streaming
|
|
460
546
|
|
|
461
|
-
See [examples/fastapi_websocket.py](examples/fastapi_websocket.py) for a complete example
|
|
547
|
+
See [examples/fastapi_websocket.py](examples/fastapi_websocket.py) for a complete example using `FastAPIAdapter` to stream LangGraph events to a web client.
|
|
462
548
|
|
|
463
549
|
```bash
|
|
464
550
|
# Install dependencies
|
|
465
|
-
pip install fastapi uvicorn
|
|
551
|
+
pip install 'langgraph-stream-parser[fastapi]' uvicorn
|
|
466
552
|
|
|
467
553
|
# Run the example
|
|
468
554
|
uvicorn examples.fastapi_websocket:app --reload
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="assets/header.svg" alt="langgraph-stream-parser" width="100%">
|
|
3
|
+
</p>
|
|
4
|
+
|
|
1
5
|
# langgraph-stream-parser
|
|
2
6
|
|
|
3
7
|
Universal parser for LangGraph streaming outputs. Normalizes complex, variable output shapes from `graph.stream()` and `graph.astream()` into consistent, typed event objects.
|
|
@@ -43,13 +47,17 @@ for event in parser.parse(graph.stream(input_data, stream_mode="updates")):
|
|
|
43
47
|
| Event | Description |
|
|
44
48
|
|-------|-------------|
|
|
45
49
|
| `ContentEvent` | Text content from AI messages. Includes `agent_name` when from a deep agent subagent. |
|
|
50
|
+
| `ReasoningEvent` | Reasoning / thinking text — from langchain-core `reasoning` content blocks or `think_tool` reflections |
|
|
46
51
|
| `ToolCallStartEvent` | Tool call initiated by AI |
|
|
47
52
|
| `ToolCallEndEvent` | Tool call completed with result |
|
|
48
|
-
| `ToolExtractedEvent` | Special content extracted from tool (e.g.,
|
|
53
|
+
| `ToolExtractedEvent` | Special content extracted from tool (e.g., todos, custom extractors) |
|
|
54
|
+
| `DisplayEvent` | Rich inline content (dataframe, image, plotly, html, json) from `display_inline`-style tools |
|
|
49
55
|
| `InterruptEvent` | Human-in-the-loop interrupt requiring decision |
|
|
50
56
|
| `StateUpdateEvent` | Non-message state updates (opt-in) |
|
|
51
|
-
| `UsageEvent` | Token usage metadata (input/output/total tokens) |
|
|
57
|
+
| `UsageEvent` | Token usage metadata (input/output/total/cache_read/cache_creation tokens) |
|
|
52
58
|
| `CustomEvent` | Custom data emitted via `get_stream_writer()` |
|
|
59
|
+
| `ValuesEvent` | Full state snapshot from `stream_mode="values"` (v2) |
|
|
60
|
+
| `DebugEvent` | Debug, checkpoint, or task trace from v2 streaming |
|
|
53
61
|
| `CompleteEvent` | Stream finished successfully |
|
|
54
62
|
| `ErrorEvent` | Error during streaming |
|
|
55
63
|
|
|
@@ -131,6 +139,22 @@ for event in parser.parse(graph.stream(input_data, config=config)):
|
|
|
131
139
|
break
|
|
132
140
|
```
|
|
133
141
|
|
|
142
|
+
Supported decision types (deepagents 0.6+ / LangGraph 1.1+): `"approve"`, `"reject"`, `"edit"`, `"respond"`.
|
|
143
|
+
|
|
144
|
+
```python
|
|
145
|
+
# Edit args before approval — emits the modern ``edited_action`` shape
|
|
146
|
+
resume = event.create_resume(
|
|
147
|
+
"edit",
|
|
148
|
+
args_modifier=lambda args: {**args, "safe": True},
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
# Reply with text in place of running the tool
|
|
152
|
+
resume = event.create_resume("respond", response="Please rephrase that.")
|
|
153
|
+
|
|
154
|
+
# For older LangGraph runtimes that expect ``{"type": "edit", "args": ...}``:
|
|
155
|
+
resume = event.create_resume("edit", args_modifier=fn, use_edited_action=False)
|
|
156
|
+
```
|
|
157
|
+
|
|
134
158
|
### Custom Tool Extractors
|
|
135
159
|
|
|
136
160
|
```python
|
|
@@ -213,12 +237,14 @@ for event in parser.parse(stream):
|
|
|
213
237
|
print(event.content, end="")
|
|
214
238
|
```
|
|
215
239
|
|
|
216
|
-
For [LangChain deep agents](https://docs.langchain.com/oss/python/deepagents/subagents), `ContentEvent.agent_name` is extracted from `lc_agent_name` metadata:
|
|
240
|
+
For [LangChain deep agents](https://docs.langchain.com/oss/python/deepagents/subagents), `ContentEvent.agent_name` is extracted from `lc_agent_name` metadata, and `ContentEvent.is_subagent` is set to `True` when deepagents (>= 0.6) tags the run with `ls_agent_type="subagent"`. Match on either signal:
|
|
217
241
|
|
|
218
242
|
```python
|
|
219
|
-
case ContentEvent(content=text, agent_name=name):
|
|
220
|
-
label = f"[{name}] "
|
|
243
|
+
case ContentEvent(content=text, agent_name=name, is_subagent=True):
|
|
244
|
+
label = f"[{name or 'subagent'}] "
|
|
221
245
|
print(f"{label}{text}", end="")
|
|
246
|
+
case ContentEvent(content=text):
|
|
247
|
+
print(text, end="")
|
|
222
248
|
```
|
|
223
249
|
|
|
224
250
|
### Custom Stream Mode
|
|
@@ -234,6 +260,60 @@ for event in parser.parse(stream):
|
|
|
234
260
|
print(f"Progress: {data}")
|
|
235
261
|
```
|
|
236
262
|
|
|
263
|
+
### Reasoning & Thinking
|
|
264
|
+
|
|
265
|
+
Reasoning content arrives as a distinct `ReasoningEvent` so UIs can render it differently from the final answer (greyed out, collapsed, etc.). Two sources, same event type:
|
|
266
|
+
|
|
267
|
+
```python
|
|
268
|
+
for event in parser.parse(stream):
|
|
269
|
+
match event:
|
|
270
|
+
case ReasoningEvent(content=text, source="content_block"):
|
|
271
|
+
# From langchain-core reasoning blocks (Anthropic thinking,
|
|
272
|
+
# OpenAI reasoning summaries). Streamed token-by-token.
|
|
273
|
+
print(f"\033[90m{text}\033[0m", end="") # grey
|
|
274
|
+
case ReasoningEvent(content=text, source="think_tool"):
|
|
275
|
+
# From the built-in think_tool ThinkToolExtractor.
|
|
276
|
+
print(f"💭 {text}")
|
|
277
|
+
case ContentEvent(content=text):
|
|
278
|
+
print(text, end="")
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
### Rich Inline Display
|
|
282
|
+
|
|
283
|
+
For agents that need to show DataFrames, charts, images, or HTML in the transcript, use a `display_inline`-style tool. The parser recognizes the convention and emits a typed `DisplayEvent` — no stringified dict hacks.
|
|
284
|
+
|
|
285
|
+
**Tool side** — return a JSON string with `display_type`, `data`, `title`, `status`:
|
|
286
|
+
|
|
287
|
+
```python
|
|
288
|
+
def show_dataframe(df_name: str) -> str:
|
|
289
|
+
import json
|
|
290
|
+
df = load(df_name)
|
|
291
|
+
return json.dumps({
|
|
292
|
+
"type": "display_inline",
|
|
293
|
+
"display_type": "dataframe",
|
|
294
|
+
"title": df_name,
|
|
295
|
+
"data": df.to_html(), # or fig.to_json() for plotly,
|
|
296
|
+
"status": "success", # base64 PNG for matplotlib, etc.
|
|
297
|
+
})
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
Configure your LangGraph tool registration with `name="display_inline"` (or register a custom `DisplayInlineExtractor` for a different name).
|
|
301
|
+
|
|
302
|
+
**Consumer side** — match on `DisplayEvent`:
|
|
303
|
+
|
|
304
|
+
```python
|
|
305
|
+
for event in parser.parse(stream):
|
|
306
|
+
match event:
|
|
307
|
+
case DisplayEvent(display_type="dataframe", data=html, title=title):
|
|
308
|
+
ui.show_html(f"<h3>{title}</h3>{html}")
|
|
309
|
+
case DisplayEvent(display_type="plotly", data=plotly_json):
|
|
310
|
+
ui.show_plotly(json.loads(plotly_json))
|
|
311
|
+
case DisplayEvent(display_type=kind, data=data):
|
|
312
|
+
ui.show_generic(kind, data)
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
The `display_type` field is consumer-defined — any string the tool and UI agree on. Common values: `"dataframe"`, `"image"`, `"plotly"`, `"html"`, `"json"`.
|
|
316
|
+
|
|
237
317
|
### Configuration Options
|
|
238
318
|
|
|
239
319
|
```python
|
|
@@ -415,16 +495,17 @@ The package includes extractors for common LangGraph tools:
|
|
|
415
495
|
|
|
416
496
|
- **ThinkToolExtractor**: Extracts reflections from `think_tool`
|
|
417
497
|
- **TodoExtractor**: Extracts todo lists from `write_todos`
|
|
498
|
+
- **DisplayInlineExtractor**: Extracts inline display artifacts from `display_inline`
|
|
418
499
|
|
|
419
500
|
## Examples
|
|
420
501
|
|
|
421
502
|
### FastAPI WebSocket Streaming
|
|
422
503
|
|
|
423
|
-
See [examples/fastapi_websocket.py](examples/fastapi_websocket.py) for a complete example
|
|
504
|
+
See [examples/fastapi_websocket.py](examples/fastapi_websocket.py) for a complete example using `FastAPIAdapter` to stream LangGraph events to a web client.
|
|
424
505
|
|
|
425
506
|
```bash
|
|
426
507
|
# Install dependencies
|
|
427
|
-
pip install fastapi uvicorn
|
|
508
|
+
pip install 'langgraph-stream-parser[fastapi]' uvicorn
|
|
428
509
|
|
|
429
510
|
# Run the example
|
|
430
511
|
uvicorn examples.fastapi_websocket:app --reload
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="1280" height="340" viewBox="0 0 1280 340" role="img" aria-label="langgraph-stream-parser — typed events and adapters for LangGraph streaming output">
|
|
2
|
+
<defs>
|
|
3
|
+
<linearGradient id="bg" x1="0" y1="0" x2="1" y2="1">
|
|
4
|
+
<stop offset="0" stop-color="#0B1221"/>
|
|
5
|
+
<stop offset="1" stop-color="#121226"/>
|
|
6
|
+
</linearGradient>
|
|
7
|
+
<linearGradient id="accent" x1="0" y1="0" x2="1" y2="0">
|
|
8
|
+
<stop offset="0" stop-color="#7C5CFF"/>
|
|
9
|
+
<stop offset="1" stop-color="#34D6C8"/>
|
|
10
|
+
</linearGradient>
|
|
11
|
+
<radialGradient id="glow" cx="0.82" cy="0.15" r="0.6">
|
|
12
|
+
<stop offset="0" stop-color="#7C5CFF" stop-opacity="0.22"/>
|
|
13
|
+
<stop offset="1" stop-color="#7C5CFF" stop-opacity="0"/>
|
|
14
|
+
</radialGradient>
|
|
15
|
+
</defs>
|
|
16
|
+
|
|
17
|
+
<rect width="1280" height="340" rx="20" fill="url(#bg)"/>
|
|
18
|
+
<rect width="1280" height="340" rx="20" fill="url(#glow)"/>
|
|
19
|
+
<rect x="1" y="1" width="1278" height="338" rx="19" fill="none" stroke="#26284A" stroke-width="1.5"/>
|
|
20
|
+
|
|
21
|
+
<!-- ===== left: identity ===== -->
|
|
22
|
+
<g transform="translate(72,64)">
|
|
23
|
+
<rect width="92" height="34" rx="17" fill="#1A1535" stroke="url(#accent)" stroke-width="1.5"/>
|
|
24
|
+
<circle cx="22" cy="17" r="5" fill="url(#accent)"/>
|
|
25
|
+
<text x="38" y="23" font-family="'SF Mono','JetBrains Mono','Consolas',monospace" font-size="15" fill="#C9BEFF">v0.2</text>
|
|
26
|
+
</g>
|
|
27
|
+
|
|
28
|
+
<text x="70" y="176" font-family="'SF Mono','JetBrains Mono','Consolas',monospace" font-size="50" font-weight="700" fill="#F2F6FC" letter-spacing="-1">langgraph<tspan fill="url(#accent)">-stream-parser</tspan></text>
|
|
29
|
+
|
|
30
|
+
<text x="72" y="220" font-family="'Segoe UI',Helvetica,Arial,sans-serif" font-size="22" fill="#A6AECB">Typed events & adapters for LangGraph streaming output.</text>
|
|
31
|
+
<text x="72" y="250" font-family="'Segoe UI',Helvetica,Arial,sans-serif" font-size="22" fill="#A6AECB">The shared runtime behind the deep-agent surfaces.</text>
|
|
32
|
+
|
|
33
|
+
<g font-family="'SF Mono','JetBrains Mono','Consolas',monospace" font-size="13" fill="#7C7FA6">
|
|
34
|
+
<text x="72" y="298">StreamParser</text>
|
|
35
|
+
<text x="196" y="298" fill="#45487A">•</text>
|
|
36
|
+
<text x="216" y="298">extractors</text>
|
|
37
|
+
<text x="312" y="298" fill="#45487A">•</text>
|
|
38
|
+
<text x="332" y="298">adapters</text>
|
|
39
|
+
<text x="420" y="298" fill="#45487A">•</text>
|
|
40
|
+
<text x="440" y="298">host · demo</text>
|
|
41
|
+
</g>
|
|
42
|
+
|
|
43
|
+
<!-- ===== right: stream -> typed events ===== -->
|
|
44
|
+
<g transform="translate(840,86)">
|
|
45
|
+
<!-- source: graph.stream() -->
|
|
46
|
+
<rect width="150" height="40" rx="10" fill="#161433" stroke="#3A2F66" stroke-width="1.5"/>
|
|
47
|
+
<text x="18" y="25" font-family="'SF Mono','Consolas',monospace" font-size="13" fill="#9FB0CC">graph.stream()</text>
|
|
48
|
+
|
|
49
|
+
<!-- arrow -->
|
|
50
|
+
<line x1="150" y1="20" x2="196" y2="20" stroke="url(#accent)" stroke-width="2"/>
|
|
51
|
+
<path d="M196 20 l-9 -5 v10 z" fill="#34D6C8"/>
|
|
52
|
+
|
|
53
|
+
<!-- parser node -->
|
|
54
|
+
<rect x="196" y="2" width="118" height="36" rx="10" fill="#1A1535" stroke="url(#accent)" stroke-width="1.5"/>
|
|
55
|
+
<circle cx="216" cy="20" r="5" fill="url(#accent)"/>
|
|
56
|
+
<text x="230" y="25" font-family="'SF Mono','Consolas',monospace" font-size="12" fill="#C9BEFF">parse()</text>
|
|
57
|
+
|
|
58
|
+
<!-- typed event chips -->
|
|
59
|
+
<g font-family="'SF Mono','Consolas',monospace" font-size="12">
|
|
60
|
+
<g transform="translate(40,72)">
|
|
61
|
+
<rect width="130" height="26" rx="6" fill="#10243A" stroke="#2F9BFF" stroke-width="1"/>
|
|
62
|
+
<circle cx="15" cy="13" r="4" fill="#2F9BFF"/>
|
|
63
|
+
<text x="28" y="17" fill="#8FC4FF">ContentEvent</text>
|
|
64
|
+
</g>
|
|
65
|
+
<g transform="translate(190,72)">
|
|
66
|
+
<rect width="150" height="26" rx="6" fill="#0C2A22" stroke="#34D6C8" stroke-width="1"/>
|
|
67
|
+
<circle cx="15" cy="13" r="4" fill="#34D6C8"/>
|
|
68
|
+
<text x="28" y="17" fill="#7FE3D6">ToolCallStart</text>
|
|
69
|
+
</g>
|
|
70
|
+
<g transform="translate(40,108)">
|
|
71
|
+
<rect width="150" height="26" rx="6" fill="#0C2A22" stroke="#34D6C8" stroke-width="1"/>
|
|
72
|
+
<circle cx="15" cy="13" r="4" fill="#34D6C8"/>
|
|
73
|
+
<text x="28" y="17" fill="#7FE3D6">ToolCallEnd</text>
|
|
74
|
+
</g>
|
|
75
|
+
<g transform="translate(210,108)">
|
|
76
|
+
<rect width="130" height="26" rx="6" fill="#241A33" stroke="#7C5CFF" stroke-width="1"/>
|
|
77
|
+
<circle cx="15" cy="13" r="4" fill="#7C5CFF"/>
|
|
78
|
+
<text x="28" y="17" fill="#C9BEFF">Interrupt</text>
|
|
79
|
+
</g>
|
|
80
|
+
<g transform="translate(40,144)">
|
|
81
|
+
<rect width="180" height="26" rx="6" fill="#10243A" stroke="#2F9BFF" stroke-width="1"/>
|
|
82
|
+
<circle cx="15" cy="13" r="4" fill="#2F9BFF"/>
|
|
83
|
+
<text x="28" y="17" fill="#8FC4FF">Reasoning · Display …</text>
|
|
84
|
+
</g>
|
|
85
|
+
</g>
|
|
86
|
+
</g>
|
|
87
|
+
</svg>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "langgraph-stream-parser"
|
|
3
|
-
version = "0.1
|
|
3
|
+
version = "0.2.1"
|
|
4
4
|
description = "Universal parser for LangGraph streaming outputs"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = {text = "MIT"}
|
|
@@ -38,12 +38,19 @@ jupyter = [
|
|
|
38
38
|
fastapi = [
|
|
39
39
|
"fastapi>=0.100",
|
|
40
40
|
]
|
|
41
|
+
demo = [
|
|
42
|
+
"deepagents>=0.3",
|
|
43
|
+
]
|
|
44
|
+
real = [
|
|
45
|
+
"langchain-openai>=0.2",
|
|
46
|
+
"langgraph>=1.1.0",
|
|
47
|
+
]
|
|
41
48
|
dev = [
|
|
42
49
|
"pytest>=7.0",
|
|
43
50
|
"pytest-asyncio>=0.21",
|
|
44
51
|
"pytest-cov>=4.0",
|
|
45
|
-
"langgraph>=
|
|
46
|
-
"langchain-core>=
|
|
52
|
+
"langgraph>=1.1.0",
|
|
53
|
+
"langchain-core>=1.4.0",
|
|
47
54
|
"rich>=13.0",
|
|
48
55
|
"fastapi>=0.100",
|
|
49
56
|
"httpx>=0.25",
|
|
@@ -65,6 +72,9 @@ packages = ["src/langgraph_stream_parser"]
|
|
|
65
72
|
[tool.pytest.ini_options]
|
|
66
73
|
asyncio_mode = "auto"
|
|
67
74
|
testpaths = ["tests"]
|
|
75
|
+
markers = [
|
|
76
|
+
"real_model: hits a live LLM via OpenRouter (opt-in; skips without OPENROUTER_API_KEY)",
|
|
77
|
+
]
|
|
68
78
|
|
|
69
79
|
[tool.coverage.run]
|
|
70
80
|
source = ["src/langgraph_stream_parser"]
|
|
@@ -32,9 +32,11 @@ Legacy Dict-Based API:
|
|
|
32
32
|
from .parser import StreamParser
|
|
33
33
|
from .events import (
|
|
34
34
|
ContentEvent,
|
|
35
|
+
ReasoningEvent,
|
|
35
36
|
ToolCallStartEvent,
|
|
36
37
|
ToolCallEndEvent,
|
|
37
38
|
ToolExtractedEvent,
|
|
39
|
+
DisplayEvent,
|
|
38
40
|
InterruptEvent,
|
|
39
41
|
StateUpdateEvent,
|
|
40
42
|
UsageEvent,
|
|
@@ -47,8 +49,14 @@ from .events import (
|
|
|
47
49
|
event_to_dict,
|
|
48
50
|
)
|
|
49
51
|
from .extractors.base import ToolExtractor
|
|
50
|
-
from .extractors.builtins import
|
|
52
|
+
from .extractors.builtins import (
|
|
53
|
+
DisplayInlineExtractor,
|
|
54
|
+
GenericToolExtractor,
|
|
55
|
+
ThinkToolExtractor,
|
|
56
|
+
TodoExtractor,
|
|
57
|
+
)
|
|
51
58
|
from .resume import create_resume_input, prepare_agent_input
|
|
59
|
+
from .host import load_agent_spec, HostConfig, Workspace
|
|
52
60
|
from .compat import (
|
|
53
61
|
stream_graph_updates,
|
|
54
62
|
astream_graph_updates,
|
|
@@ -56,16 +64,18 @@ from .compat import (
|
|
|
56
64
|
aresume_graph_from_interrupt,
|
|
57
65
|
)
|
|
58
66
|
|
|
59
|
-
__version__ = "0.1
|
|
67
|
+
__version__ = "0.2.1"
|
|
60
68
|
|
|
61
69
|
__all__ = [
|
|
62
70
|
# Main parser
|
|
63
71
|
"StreamParser",
|
|
64
72
|
# Event types
|
|
65
73
|
"ContentEvent",
|
|
74
|
+
"ReasoningEvent",
|
|
66
75
|
"ToolCallStartEvent",
|
|
67
76
|
"ToolCallEndEvent",
|
|
68
77
|
"ToolExtractedEvent",
|
|
78
|
+
"DisplayEvent",
|
|
69
79
|
"InterruptEvent",
|
|
70
80
|
"StateUpdateEvent",
|
|
71
81
|
"UsageEvent",
|
|
@@ -80,9 +90,14 @@ __all__ = [
|
|
|
80
90
|
"ThinkToolExtractor",
|
|
81
91
|
"TodoExtractor",
|
|
82
92
|
"DisplayInlineExtractor",
|
|
93
|
+
"GenericToolExtractor",
|
|
83
94
|
# Resume utilities
|
|
84
95
|
"create_resume_input",
|
|
85
96
|
"prepare_agent_input",
|
|
97
|
+
# Host conventions
|
|
98
|
+
"load_agent_spec",
|
|
99
|
+
"HostConfig",
|
|
100
|
+
"Workspace",
|
|
86
101
|
# Serialization
|
|
87
102
|
"event_to_dict",
|
|
88
103
|
# Legacy/compat functions
|
|
@@ -4,6 +4,7 @@ from .base import BaseAdapter, ToolStatus, ToolState
|
|
|
4
4
|
from .print import PrintAdapter
|
|
5
5
|
from .cli import CLIAdapter
|
|
6
6
|
from .fastapi import FastAPIAdapter
|
|
7
|
+
from .session import SessionAdapter, Session
|
|
7
8
|
|
|
8
9
|
__all__ = [
|
|
9
10
|
"BaseAdapter",
|
|
@@ -12,4 +13,6 @@ __all__ = [
|
|
|
12
13
|
"PrintAdapter",
|
|
13
14
|
"CLIAdapter",
|
|
14
15
|
"FastAPIAdapter",
|
|
16
|
+
"SessionAdapter",
|
|
17
|
+
"Session",
|
|
15
18
|
]
|