pixelgraph 0.1.0__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.
- pixelgraph-0.1.0/LICENSE +21 -0
- pixelgraph-0.1.0/MANIFEST.in +4 -0
- pixelgraph-0.1.0/PKG-INFO +207 -0
- pixelgraph-0.1.0/README.md +167 -0
- pixelgraph-0.1.0/pixelgraph/__init__.py +12 -0
- pixelgraph-0.1.0/pixelgraph/callback.py +199 -0
- pixelgraph-0.1.0/pixelgraph/cli.py +143 -0
- pixelgraph-0.1.0/pixelgraph/schemas/__init__.py +10 -0
- pixelgraph-0.1.0/pixelgraph/schemas/events.py +63 -0
- pixelgraph-0.1.0/pixelgraph/server.py +324 -0
- pixelgraph-0.1.0/pixelgraph/static/assets/index-BoARAmk4.js +6399 -0
- pixelgraph-0.1.0/pixelgraph/static/assets/index-DQy_14IR.css +1 -0
- pixelgraph-0.1.0/pixelgraph/static/assets/sprites/wizard.svg +37 -0
- pixelgraph-0.1.0/pixelgraph/static/index.html +37 -0
- pixelgraph-0.1.0/pixelgraph.egg-info/PKG-INFO +207 -0
- pixelgraph-0.1.0/pixelgraph.egg-info/SOURCES.txt +23 -0
- pixelgraph-0.1.0/pixelgraph.egg-info/dependency_links.txt +1 -0
- pixelgraph-0.1.0/pixelgraph.egg-info/entry_points.txt +2 -0
- pixelgraph-0.1.0/pixelgraph.egg-info/requires.txt +21 -0
- pixelgraph-0.1.0/pixelgraph.egg-info/top_level.txt +1 -0
- pixelgraph-0.1.0/pyproject.toml +79 -0
- pixelgraph-0.1.0/requirements.txt +17 -0
- pixelgraph-0.1.0/setup.cfg +4 -0
- pixelgraph-0.1.0/tests/test_callback.py +90 -0
- pixelgraph-0.1.0/tests/test_server.py +87 -0
pixelgraph-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Дiegushko Хименес
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pixelgraph
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: 8-bit visualization for LangGraph agents
|
|
5
|
+
Author-email: Diego <diego@example.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/diegonov1/PixelGraph
|
|
8
|
+
Project-URL: Repository, https://github.com/diegonov1/PixelGraph
|
|
9
|
+
Project-URL: Issues, https://github.com/diegonov1/PixelGraph/issues
|
|
10
|
+
Keywords: langgraph,langchain,visualization,8-bit,agents,ai
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
19
|
+
Requires-Python: >=3.10
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
License-File: LICENSE
|
|
22
|
+
Requires-Dist: fastapi>=0.104.0
|
|
23
|
+
Requires-Dist: uvicorn[standard]>=0.24.0
|
|
24
|
+
Requires-Dist: pydantic>=2.0.0
|
|
25
|
+
Requires-Dist: websockets>=12.0
|
|
26
|
+
Requires-Dist: langchain-core>=0.1.0
|
|
27
|
+
Provides-Extra: dev
|
|
28
|
+
Requires-Dist: pytest>=7.4.0; extra == "dev"
|
|
29
|
+
Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
|
|
30
|
+
Requires-Dist: httpx>=0.25.0; extra == "dev"
|
|
31
|
+
Requires-Dist: black>=23.0.0; extra == "dev"
|
|
32
|
+
Requires-Dist: mypy>=1.0.0; extra == "dev"
|
|
33
|
+
Provides-Extra: langgraph
|
|
34
|
+
Requires-Dist: langgraph>=0.0.40; extra == "langgraph"
|
|
35
|
+
Provides-Extra: openai
|
|
36
|
+
Requires-Dist: langchain-openai>=0.0.5; extra == "openai"
|
|
37
|
+
Provides-Extra: all
|
|
38
|
+
Requires-Dist: pixelgraph[dev,langgraph,openai]; extra == "all"
|
|
39
|
+
Dynamic: license-file
|
|
40
|
+
|
|
41
|
+
# PixelGraph
|
|
42
|
+
|
|
43
|
+
> 8-bit visualization for LangGraph agents
|
|
44
|
+
|
|
45
|
+
PixelGraph transforms your LangGraph agent interactions into a retro 8-bit game experience. Watch your AI agents think, speak, and use tools in a nostalgic pixel-art environment.
|
|
46
|
+
|
|
47
|
+
## Features
|
|
48
|
+
|
|
49
|
+
- **Drop-in Integration**: Works with any existing LangGraph application
|
|
50
|
+
- **Real-time Visualization**: See agent thoughts, speech, and tool usage
|
|
51
|
+
- **8-bit Aesthetics**: Pixel art sprites and retro styling
|
|
52
|
+
- **WebSocket Communication**: Bidirectional real-time updates
|
|
53
|
+
- **Action Queue**: Smooth animation sequencing regardless of event speed
|
|
54
|
+
|
|
55
|
+
## Quick Start
|
|
56
|
+
|
|
57
|
+
### Installation
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
# Clone the repository
|
|
61
|
+
git clone https://github.com/diegonov1/PixelGraph.git
|
|
62
|
+
cd PixelGraph
|
|
63
|
+
|
|
64
|
+
# Install Python dependencies
|
|
65
|
+
pip install -r requirements.txt
|
|
66
|
+
|
|
67
|
+
# Install frontend dependencies
|
|
68
|
+
cd frontend && npm install && cd ..
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Run Demo Mode
|
|
72
|
+
|
|
73
|
+
Without any LLM API key, you can run the demo:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
# Terminal 1: Start backend
|
|
77
|
+
python examples/simple_demo.py
|
|
78
|
+
|
|
79
|
+
# Terminal 2: Start frontend
|
|
80
|
+
cd frontend && npm run dev
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Open http://localhost:3000 in your browser.
|
|
84
|
+
|
|
85
|
+
### Run with LangGraph
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
# Set your OpenAI API key
|
|
89
|
+
export OPENAI_API_KEY=your-api-key
|
|
90
|
+
|
|
91
|
+
# Run the LangGraph example
|
|
92
|
+
python examples/langgraph_example.py
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Usage
|
|
96
|
+
|
|
97
|
+
Integrate PixelGraph with your existing LangGraph application:
|
|
98
|
+
|
|
99
|
+
```python
|
|
100
|
+
from langgraph.graph import StateGraph
|
|
101
|
+
from pixelgraph import GameServer
|
|
102
|
+
|
|
103
|
+
# Your existing LangGraph code
|
|
104
|
+
graph = StateGraph(State)
|
|
105
|
+
# ... add nodes and edges ...
|
|
106
|
+
app = graph.compile()
|
|
107
|
+
|
|
108
|
+
# Add visualization with one line
|
|
109
|
+
server = GameServer(app)
|
|
110
|
+
server.serve()
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Visual Configuration
|
|
114
|
+
|
|
115
|
+
Customize how agents appear in the game:
|
|
116
|
+
|
|
117
|
+
```python
|
|
118
|
+
from pixelgraph import GameServer
|
|
119
|
+
from pixelgraph.schemas.events import VisualConfig, AgentConfig
|
|
120
|
+
|
|
121
|
+
config = VisualConfig(
|
|
122
|
+
title="My Agent Team",
|
|
123
|
+
theme="dungeon",
|
|
124
|
+
nodes={
|
|
125
|
+
"researcher": AgentConfig(sprite="wizard", color="blue"),
|
|
126
|
+
"writer": AgentConfig(sprite="bard", color="red"),
|
|
127
|
+
}
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
server = GameServer(app, config=config)
|
|
131
|
+
server.serve()
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## Architecture
|
|
135
|
+
|
|
136
|
+
```
|
|
137
|
+
Frontend (React + Phaser) Backend (FastAPI + LangGraph)
|
|
138
|
+
┌─────────────┐ ┌─────────────┐
|
|
139
|
+
│ Phaser │◄─WebSocket──►│ GameServer │
|
|
140
|
+
│ Canvas │ │ │
|
|
141
|
+
└─────────────┘ │ Callback │
|
|
142
|
+
┌─────────────┐ │ Handler │
|
|
143
|
+
│ React │ │ ▲ │
|
|
144
|
+
│ HUD/Log │ │ │ │
|
|
145
|
+
└─────────────┘ │ LangGraph │
|
|
146
|
+
└─────────────┘
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### Event Flow
|
|
150
|
+
|
|
151
|
+
1. LangGraph emits events during execution
|
|
152
|
+
2. `GameVisualizerCallbackHandler` captures and transforms events
|
|
153
|
+
3. Events are sent via WebSocket to the frontend
|
|
154
|
+
4. Frontend queues events in the `ActionQueue`
|
|
155
|
+
5. Phaser consumes events one at a time, playing animations
|
|
156
|
+
|
|
157
|
+
## Development
|
|
158
|
+
|
|
159
|
+
### Project Structure
|
|
160
|
+
|
|
161
|
+
```
|
|
162
|
+
pixelgraph/
|
|
163
|
+
├── pixelgraph/ # Python package
|
|
164
|
+
│ ├── __init__.py # Package exports
|
|
165
|
+
│ ├── callback.py # LangChain callback handler
|
|
166
|
+
│ ├── server.py # FastAPI WebSocket server
|
|
167
|
+
│ ├── schemas/ # Pydantic event schemas
|
|
168
|
+
│ └── static/ # Built frontend (after npm build)
|
|
169
|
+
├── frontend/ # React + Phaser frontend
|
|
170
|
+
│ ├── src/
|
|
171
|
+
│ │ ├── game/ # Phaser logic
|
|
172
|
+
│ │ │ ├── scenes/ # Game scenes
|
|
173
|
+
│ │ │ ├── entities/# Sprite classes
|
|
174
|
+
│ │ │ └── systems/ # Event bus, action queue
|
|
175
|
+
│ │ └── components/ # React UI components
|
|
176
|
+
│ └── public/assets/ # Sprites and assets
|
|
177
|
+
├── examples/ # Usage examples
|
|
178
|
+
└── tests/ # Test suite
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### Commands
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
make install # Install all dependencies
|
|
185
|
+
make dev # Run both backend and frontend
|
|
186
|
+
make build # Build frontend for production
|
|
187
|
+
make test # Run tests
|
|
188
|
+
make docker-dev # Run with Docker (development)
|
|
189
|
+
make docker-prod # Run with Docker (production)
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
## Roadmap
|
|
193
|
+
|
|
194
|
+
- [ ] Multi-agent support with dynamic positioning
|
|
195
|
+
- [ ] Tool-specific animations (search, calculator, etc.)
|
|
196
|
+
- [ ] Speed control for event playback
|
|
197
|
+
- [ ] Custom sprite support
|
|
198
|
+
- [ ] Themes (dungeon, sci-fi, city)
|
|
199
|
+
- [ ] Export conversation as GIF
|
|
200
|
+
|
|
201
|
+
## License
|
|
202
|
+
|
|
203
|
+
MIT
|
|
204
|
+
|
|
205
|
+
## Contributing
|
|
206
|
+
|
|
207
|
+
Contributions welcome! Please read our contributing guidelines first.
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
# PixelGraph
|
|
2
|
+
|
|
3
|
+
> 8-bit visualization for LangGraph agents
|
|
4
|
+
|
|
5
|
+
PixelGraph transforms your LangGraph agent interactions into a retro 8-bit game experience. Watch your AI agents think, speak, and use tools in a nostalgic pixel-art environment.
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- **Drop-in Integration**: Works with any existing LangGraph application
|
|
10
|
+
- **Real-time Visualization**: See agent thoughts, speech, and tool usage
|
|
11
|
+
- **8-bit Aesthetics**: Pixel art sprites and retro styling
|
|
12
|
+
- **WebSocket Communication**: Bidirectional real-time updates
|
|
13
|
+
- **Action Queue**: Smooth animation sequencing regardless of event speed
|
|
14
|
+
|
|
15
|
+
## Quick Start
|
|
16
|
+
|
|
17
|
+
### Installation
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
# Clone the repository
|
|
21
|
+
git clone https://github.com/diegonov1/PixelGraph.git
|
|
22
|
+
cd PixelGraph
|
|
23
|
+
|
|
24
|
+
# Install Python dependencies
|
|
25
|
+
pip install -r requirements.txt
|
|
26
|
+
|
|
27
|
+
# Install frontend dependencies
|
|
28
|
+
cd frontend && npm install && cd ..
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Run Demo Mode
|
|
32
|
+
|
|
33
|
+
Without any LLM API key, you can run the demo:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
# Terminal 1: Start backend
|
|
37
|
+
python examples/simple_demo.py
|
|
38
|
+
|
|
39
|
+
# Terminal 2: Start frontend
|
|
40
|
+
cd frontend && npm run dev
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Open http://localhost:3000 in your browser.
|
|
44
|
+
|
|
45
|
+
### Run with LangGraph
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
# Set your OpenAI API key
|
|
49
|
+
export OPENAI_API_KEY=your-api-key
|
|
50
|
+
|
|
51
|
+
# Run the LangGraph example
|
|
52
|
+
python examples/langgraph_example.py
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Usage
|
|
56
|
+
|
|
57
|
+
Integrate PixelGraph with your existing LangGraph application:
|
|
58
|
+
|
|
59
|
+
```python
|
|
60
|
+
from langgraph.graph import StateGraph
|
|
61
|
+
from pixelgraph import GameServer
|
|
62
|
+
|
|
63
|
+
# Your existing LangGraph code
|
|
64
|
+
graph = StateGraph(State)
|
|
65
|
+
# ... add nodes and edges ...
|
|
66
|
+
app = graph.compile()
|
|
67
|
+
|
|
68
|
+
# Add visualization with one line
|
|
69
|
+
server = GameServer(app)
|
|
70
|
+
server.serve()
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Visual Configuration
|
|
74
|
+
|
|
75
|
+
Customize how agents appear in the game:
|
|
76
|
+
|
|
77
|
+
```python
|
|
78
|
+
from pixelgraph import GameServer
|
|
79
|
+
from pixelgraph.schemas.events import VisualConfig, AgentConfig
|
|
80
|
+
|
|
81
|
+
config = VisualConfig(
|
|
82
|
+
title="My Agent Team",
|
|
83
|
+
theme="dungeon",
|
|
84
|
+
nodes={
|
|
85
|
+
"researcher": AgentConfig(sprite="wizard", color="blue"),
|
|
86
|
+
"writer": AgentConfig(sprite="bard", color="red"),
|
|
87
|
+
}
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
server = GameServer(app, config=config)
|
|
91
|
+
server.serve()
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Architecture
|
|
95
|
+
|
|
96
|
+
```
|
|
97
|
+
Frontend (React + Phaser) Backend (FastAPI + LangGraph)
|
|
98
|
+
┌─────────────┐ ┌─────────────┐
|
|
99
|
+
│ Phaser │◄─WebSocket──►│ GameServer │
|
|
100
|
+
│ Canvas │ │ │
|
|
101
|
+
└─────────────┘ │ Callback │
|
|
102
|
+
┌─────────────┐ │ Handler │
|
|
103
|
+
│ React │ │ ▲ │
|
|
104
|
+
│ HUD/Log │ │ │ │
|
|
105
|
+
└─────────────┘ │ LangGraph │
|
|
106
|
+
└─────────────┘
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Event Flow
|
|
110
|
+
|
|
111
|
+
1. LangGraph emits events during execution
|
|
112
|
+
2. `GameVisualizerCallbackHandler` captures and transforms events
|
|
113
|
+
3. Events are sent via WebSocket to the frontend
|
|
114
|
+
4. Frontend queues events in the `ActionQueue`
|
|
115
|
+
5. Phaser consumes events one at a time, playing animations
|
|
116
|
+
|
|
117
|
+
## Development
|
|
118
|
+
|
|
119
|
+
### Project Structure
|
|
120
|
+
|
|
121
|
+
```
|
|
122
|
+
pixelgraph/
|
|
123
|
+
├── pixelgraph/ # Python package
|
|
124
|
+
│ ├── __init__.py # Package exports
|
|
125
|
+
│ ├── callback.py # LangChain callback handler
|
|
126
|
+
│ ├── server.py # FastAPI WebSocket server
|
|
127
|
+
│ ├── schemas/ # Pydantic event schemas
|
|
128
|
+
│ └── static/ # Built frontend (after npm build)
|
|
129
|
+
├── frontend/ # React + Phaser frontend
|
|
130
|
+
│ ├── src/
|
|
131
|
+
│ │ ├── game/ # Phaser logic
|
|
132
|
+
│ │ │ ├── scenes/ # Game scenes
|
|
133
|
+
│ │ │ ├── entities/# Sprite classes
|
|
134
|
+
│ │ │ └── systems/ # Event bus, action queue
|
|
135
|
+
│ │ └── components/ # React UI components
|
|
136
|
+
│ └── public/assets/ # Sprites and assets
|
|
137
|
+
├── examples/ # Usage examples
|
|
138
|
+
└── tests/ # Test suite
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### Commands
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
make install # Install all dependencies
|
|
145
|
+
make dev # Run both backend and frontend
|
|
146
|
+
make build # Build frontend for production
|
|
147
|
+
make test # Run tests
|
|
148
|
+
make docker-dev # Run with Docker (development)
|
|
149
|
+
make docker-prod # Run with Docker (production)
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
## Roadmap
|
|
153
|
+
|
|
154
|
+
- [ ] Multi-agent support with dynamic positioning
|
|
155
|
+
- [ ] Tool-specific animations (search, calculator, etc.)
|
|
156
|
+
- [ ] Speed control for event playback
|
|
157
|
+
- [ ] Custom sprite support
|
|
158
|
+
- [ ] Themes (dungeon, sci-fi, city)
|
|
159
|
+
- [ ] Export conversation as GIF
|
|
160
|
+
|
|
161
|
+
## License
|
|
162
|
+
|
|
163
|
+
MIT
|
|
164
|
+
|
|
165
|
+
## Contributing
|
|
166
|
+
|
|
167
|
+
Contributions welcome! Please read our contributing guidelines first.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"""
|
|
2
|
+
PixelGraph - 8-bit visualization for LangGraph agents
|
|
3
|
+
|
|
4
|
+
A drop-in visualization library that transforms your LangGraph
|
|
5
|
+
agent interactions into an 8-bit game experience.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from pixelgraph.server import GameServer
|
|
9
|
+
from pixelgraph.callback import GameVisualizerCallbackHandler, GameEventType
|
|
10
|
+
|
|
11
|
+
__version__ = "0.1.0"
|
|
12
|
+
__all__ = ["GameServer", "GameVisualizerCallbackHandler", "GameEventType"]
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
"""
|
|
2
|
+
GameVisualizerCallbackHandler - The bridge between LangGraph and the visualization.
|
|
3
|
+
|
|
4
|
+
This callback handler captures events from LangChain/LangGraph execution
|
|
5
|
+
and transforms them into game events for the 8-bit frontend.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import asyncio
|
|
9
|
+
from datetime import datetime
|
|
10
|
+
from typing import Any, Optional
|
|
11
|
+
from uuid import UUID, uuid4
|
|
12
|
+
|
|
13
|
+
from langchain_core.callbacks import BaseCallbackHandler
|
|
14
|
+
from langchain_core.outputs import LLMResult, ChatGeneration
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class GameEventType:
|
|
18
|
+
"""Event types that the frontend (Phaser) understands."""
|
|
19
|
+
|
|
20
|
+
AGENT_THINK_START = "AGENT_THINK_START"
|
|
21
|
+
AGENT_SPEAK = "AGENT_SPEAK"
|
|
22
|
+
TOOL_START = "TOOL_START"
|
|
23
|
+
TOOL_END = "TOOL_END"
|
|
24
|
+
AGENT_IDLE = "AGENT_IDLE"
|
|
25
|
+
ERROR = "ERROR"
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class GameVisualizerCallbackHandler(BaseCallbackHandler):
|
|
29
|
+
"""
|
|
30
|
+
Captures LangGraph/LangChain events and sends them to an async queue
|
|
31
|
+
for consumption by a WebSocket connection.
|
|
32
|
+
|
|
33
|
+
This handler acts as a "spy" that observes the execution flow without
|
|
34
|
+
interfering with it, transforming internal events into visual instructions.
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
def __init__(self, event_queue: asyncio.Queue, default_agent: str = "agent"):
|
|
38
|
+
"""
|
|
39
|
+
Initialize the callback handler.
|
|
40
|
+
|
|
41
|
+
Args:
|
|
42
|
+
event_queue: Async queue where events will be pushed
|
|
43
|
+
default_agent: Default agent name when none is specified in metadata
|
|
44
|
+
"""
|
|
45
|
+
super().__init__()
|
|
46
|
+
self.queue = event_queue
|
|
47
|
+
self.current_active_agent = default_agent
|
|
48
|
+
self._loop = None
|
|
49
|
+
|
|
50
|
+
def _get_loop(self) -> asyncio.AbstractEventLoop:
|
|
51
|
+
"""Get or create the event loop."""
|
|
52
|
+
if self._loop is None or self._loop.is_closed():
|
|
53
|
+
try:
|
|
54
|
+
self._loop = asyncio.get_running_loop()
|
|
55
|
+
except RuntimeError:
|
|
56
|
+
self._loop = asyncio.new_event_loop()
|
|
57
|
+
return self._loop
|
|
58
|
+
|
|
59
|
+
def _emit_event_sync(
|
|
60
|
+
self, event_type: str, agent_name: str, payload: dict[str, Any] | None = None
|
|
61
|
+
):
|
|
62
|
+
"""Synchronously emit an event to the queue."""
|
|
63
|
+
event = {
|
|
64
|
+
"event_id": str(uuid4()),
|
|
65
|
+
"timestamp": datetime.utcnow().isoformat(),
|
|
66
|
+
"type": event_type,
|
|
67
|
+
"agent_id": agent_name,
|
|
68
|
+
"data": payload or {},
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
loop = self._get_loop()
|
|
72
|
+
if loop.is_running():
|
|
73
|
+
asyncio.run_coroutine_threadsafe(self.queue.put(event), loop)
|
|
74
|
+
else:
|
|
75
|
+
self.queue.put_nowait(event)
|
|
76
|
+
|
|
77
|
+
async def _emit_event(
|
|
78
|
+
self, event_type: str, agent_name: str, payload: dict[str, Any] | None = None
|
|
79
|
+
):
|
|
80
|
+
"""Asynchronously emit an event to the queue."""
|
|
81
|
+
event = {
|
|
82
|
+
"event_id": str(uuid4()),
|
|
83
|
+
"timestamp": datetime.utcnow().isoformat(),
|
|
84
|
+
"type": event_type,
|
|
85
|
+
"agent_id": agent_name,
|
|
86
|
+
"data": payload or {},
|
|
87
|
+
}
|
|
88
|
+
await self.queue.put(event)
|
|
89
|
+
|
|
90
|
+
# --- Synchronous Callback Methods (for sync execution) ---
|
|
91
|
+
|
|
92
|
+
def on_chat_model_start(
|
|
93
|
+
self,
|
|
94
|
+
serialized: dict[str, Any],
|
|
95
|
+
messages: list[list[Any]],
|
|
96
|
+
*,
|
|
97
|
+
run_id: UUID,
|
|
98
|
+
parent_run_id: Optional[UUID] = None,
|
|
99
|
+
tags: Optional[list[str]] = None,
|
|
100
|
+
metadata: Optional[dict[str, Any]] = None,
|
|
101
|
+
**kwargs: Any,
|
|
102
|
+
) -> Any:
|
|
103
|
+
"""
|
|
104
|
+
Triggered when the model receives a prompt and starts processing.
|
|
105
|
+
Visual: Thought bubble '...' appears over the character.
|
|
106
|
+
"""
|
|
107
|
+
metadata = metadata or {}
|
|
108
|
+
agent_name = metadata.get("agent_name", self.current_active_agent)
|
|
109
|
+
self.current_active_agent = agent_name
|
|
110
|
+
|
|
111
|
+
self._emit_event_sync(
|
|
112
|
+
GameEventType.AGENT_THINK_START, agent_name, {"status": "processing"}
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
def on_llm_end(
|
|
116
|
+
self,
|
|
117
|
+
response: LLMResult,
|
|
118
|
+
*,
|
|
119
|
+
run_id: UUID,
|
|
120
|
+
parent_run_id: Optional[UUID] = None,
|
|
121
|
+
**kwargs: Any,
|
|
122
|
+
) -> Any:
|
|
123
|
+
"""
|
|
124
|
+
Triggered when the model has finished generating a response.
|
|
125
|
+
Visual: Speech bubble with the response text.
|
|
126
|
+
"""
|
|
127
|
+
text_content = ""
|
|
128
|
+
if response.generations:
|
|
129
|
+
generation = response.generations[0][0]
|
|
130
|
+
if isinstance(generation, ChatGeneration):
|
|
131
|
+
text_content = generation.message.content
|
|
132
|
+
else:
|
|
133
|
+
text_content = generation.text
|
|
134
|
+
|
|
135
|
+
self._emit_event_sync(
|
|
136
|
+
GameEventType.AGENT_SPEAK,
|
|
137
|
+
self.current_active_agent,
|
|
138
|
+
{"content": text_content},
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
self._emit_event_sync(GameEventType.AGENT_IDLE, self.current_active_agent)
|
|
142
|
+
|
|
143
|
+
def on_tool_start(
|
|
144
|
+
self,
|
|
145
|
+
serialized: dict[str, Any],
|
|
146
|
+
input_str: str,
|
|
147
|
+
*,
|
|
148
|
+
run_id: UUID,
|
|
149
|
+
parent_run_id: Optional[UUID] = None,
|
|
150
|
+
tags: Optional[list[str]] = None,
|
|
151
|
+
metadata: Optional[dict[str, Any]] = None,
|
|
152
|
+
**kwargs: Any,
|
|
153
|
+
) -> Any:
|
|
154
|
+
"""
|
|
155
|
+
Triggered when an agent decides to use a tool.
|
|
156
|
+
Visual: Character shows an icon (e.g., magnifying glass for web search).
|
|
157
|
+
"""
|
|
158
|
+
tool_name = serialized.get("name", "generic_tool")
|
|
159
|
+
metadata = metadata or {}
|
|
160
|
+
agent_name = metadata.get("agent_name", self.current_active_agent)
|
|
161
|
+
|
|
162
|
+
self._emit_event_sync(
|
|
163
|
+
GameEventType.TOOL_START,
|
|
164
|
+
agent_name,
|
|
165
|
+
{"tool_name": tool_name, "input_args": input_str[:100]},
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
def on_tool_end(
|
|
169
|
+
self,
|
|
170
|
+
output: str,
|
|
171
|
+
*,
|
|
172
|
+
run_id: UUID,
|
|
173
|
+
parent_run_id: Optional[UUID] = None,
|
|
174
|
+
**kwargs: Any,
|
|
175
|
+
) -> Any:
|
|
176
|
+
"""
|
|
177
|
+
Triggered when a tool finishes its work.
|
|
178
|
+
Visual: Icon disappears or character nods.
|
|
179
|
+
"""
|
|
180
|
+
self._emit_event_sync(
|
|
181
|
+
GameEventType.TOOL_END,
|
|
182
|
+
self.current_active_agent,
|
|
183
|
+
{"result_preview": output[:50] + "..." if len(output) > 50 else output},
|
|
184
|
+
)
|
|
185
|
+
|
|
186
|
+
def on_chain_error(
|
|
187
|
+
self,
|
|
188
|
+
error: BaseException,
|
|
189
|
+
*,
|
|
190
|
+
run_id: UUID,
|
|
191
|
+
parent_run_id: Optional[UUID] = None,
|
|
192
|
+
**kwargs: Any,
|
|
193
|
+
) -> Any:
|
|
194
|
+
"""Triggered when an error occurs in the chain."""
|
|
195
|
+
self._emit_event_sync(
|
|
196
|
+
GameEventType.ERROR,
|
|
197
|
+
self.current_active_agent,
|
|
198
|
+
{"error": str(error)},
|
|
199
|
+
)
|